diff --git a/src/main/java/cloud/eppo/BanditEvaluator.java b/src/main/java/cloud/eppo/BanditEvaluator.java index 4de8524..e91dd7f 100644 --- a/src/main/java/cloud/eppo/BanditEvaluator.java +++ b/src/main/java/cloud/eppo/BanditEvaluator.java @@ -6,7 +6,9 @@ import cloud.eppo.api.Attributes; import cloud.eppo.api.DiscriminableAttributes; import cloud.eppo.api.EppoValue; -import cloud.eppo.ufc.dto.*; +import cloud.eppo.api.IBanditAttributeCoefficients; +import cloud.eppo.api.IBanditCoefficients; +import cloud.eppo.api.IBanditModelData; import java.util.*; import java.util.stream.Collectors; @@ -19,7 +21,7 @@ public static BanditEvaluationResult evaluateBandit( String subjectKey, DiscriminableAttributes subjectAttributes, Actions actions, - BanditModelData modelData) { + IBanditModelData modelData) { Map actionScores = scoreActions(subjectAttributes, actions, modelData); Map actionWeights = weighActions(actionScores, modelData.getGamma(), modelData.getActionProbabilityFloor()); @@ -43,7 +45,7 @@ public static BanditEvaluationResult evaluateBandit( } private static Map scoreActions( - DiscriminableAttributes subjectAttributes, Actions actions, BanditModelData modelData) { + DiscriminableAttributes subjectAttributes, Actions actions, IBanditModelData modelData) { return actions.entrySet().stream() .collect( Collectors.toMap( @@ -53,7 +55,7 @@ private static Map scoreActions( DiscriminableAttributes actionAttributes = e.getValue(); // get all coefficients known to the model for this action - BanditCoefficients banditCoefficients = + IBanditCoefficients banditCoefficients = modelData.getCoefficients().get(actionName); if (banditCoefficients == null) { @@ -85,11 +87,11 @@ private static Map scoreActions( } private static double scoreContextForCoefficients( - Attributes attributes, Map coefficients) { + Attributes attributes, Map coefficients) { double totalScore = 0.0; - for (BanditAttributeCoefficients attributeCoefficients : coefficients.values()) { + for (IBanditAttributeCoefficients attributeCoefficients : coefficients.values()) { EppoValue contextValue = attributes.get(attributeCoefficients.getAttributeKey()); // The coefficient implementation knows how to score double attributeScore = attributeCoefficients.scoreForAttributeValue(contextValue); diff --git a/src/main/java/cloud/eppo/BaseEppoClient.java b/src/main/java/cloud/eppo/BaseEppoClient.java index 6a206c0..f421771 100644 --- a/src/main/java/cloud/eppo/BaseEppoClient.java +++ b/src/main/java/cloud/eppo/BaseEppoClient.java @@ -202,7 +202,7 @@ protected EppoValue getTypedAssignment( Configuration config = getConfiguration(); - FlagConfig flag = config.getFlag(flagKey); + IFlagConfig flag = config.getFlag(flagKey); if (flag == null) { log.warn("no configuration found for key: {}", flagKey); return defaultValue; @@ -226,7 +226,7 @@ protected EppoValue getTypedAssignment( FlagEvaluationResult evaluationResult = FlagEvaluator.evaluateFlag( flag, flagKey, subjectKey, subjectAttributes, config.isConfigObfuscated()); - EppoValue assignedValue = + IEppoValue assignedValue = evaluationResult.getVariation() != null ? evaluationResult.getVariation().getValue() : null; if (assignedValue != null && !valueTypeMatchesExpected(expectedType, assignedValue)) { @@ -278,10 +278,10 @@ protected EppoValue getTypedAssignment( log.error("Error logging assignment: {}", e.getMessage(), e); } } - return assignedValue != null ? assignedValue : defaultValue; + return assignedValue != null ? (EppoValue) assignedValue : defaultValue; } - private boolean valueTypeMatchesExpected(VariationType expectedType, EppoValue value) { + private boolean valueTypeMatchesExpected(VariationType expectedType, IEppoValue value) { boolean typeMatch; switch (expectedType) { case BOOLEAN: @@ -498,7 +498,7 @@ public BanditResult getBanditAction( String banditKey = config.banditKeyForVariation(flagKey, assignedVariation); if (banditKey != null && !actions.isEmpty()) { - BanditParameters banditParameters = config.getBanditParameters(banditKey); + IBanditParameters banditParameters = config.getBanditParameters(banditKey); BanditEvaluationResult banditResult = BanditEvaluator.evaluateBandit( flagKey, subjectKey, subjectAttributes, actions, banditParameters.getModelData()); diff --git a/src/main/java/cloud/eppo/FlagEvaluationResult.java b/src/main/java/cloud/eppo/FlagEvaluationResult.java index 18d2523..83e28b2 100644 --- a/src/main/java/cloud/eppo/FlagEvaluationResult.java +++ b/src/main/java/cloud/eppo/FlagEvaluationResult.java @@ -1,7 +1,7 @@ package cloud.eppo; import cloud.eppo.api.Attributes; -import cloud.eppo.ufc.dto.Variation; +import cloud.eppo.api.IVariation; import java.util.Map; import java.util.Objects; @@ -11,7 +11,7 @@ public class FlagEvaluationResult { private final String subjectKey; private final Attributes subjectAttributes; private final String allocationKey; - private final Variation variation; + private final IVariation variation; private final Map extraLogging; private final boolean doLog; @@ -20,7 +20,7 @@ public FlagEvaluationResult( String subjectKey, Attributes subjectAttributes, String allocationKey, - Variation variation, + IVariation variation, Map extraLogging, boolean doLog) { this.flagKey = flagKey; @@ -34,15 +34,25 @@ public FlagEvaluationResult( @Override public String toString() { - return "FlagEvaluationResult{" + - "flagKey='" + flagKey + '\'' + - ", subjectKey='" + subjectKey + '\'' + - ", subjectAttributes=" + subjectAttributes + - ", allocationKey='" + allocationKey + '\'' + - ", variation=" + variation + - ", extraLogging=" + extraLogging + - ", doLog=" + doLog + - '}'; + return "FlagEvaluationResult{" + + "flagKey='" + + flagKey + + '\'' + + ", subjectKey='" + + subjectKey + + '\'' + + ", subjectAttributes=" + + subjectAttributes + + ", allocationKey='" + + allocationKey + + '\'' + + ", variation=" + + variation + + ", extraLogging=" + + extraLogging + + ", doLog=" + + doLog + + '}'; } @Override @@ -50,17 +60,18 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; FlagEvaluationResult that = (FlagEvaluationResult) o; return doLog == that.doLog - && Objects.equals(flagKey, that.flagKey) - && Objects.equals(subjectKey, that.subjectKey) - && Objects.equals(subjectAttributes, that.subjectAttributes) - && Objects.equals(allocationKey, that.allocationKey) - && Objects.equals(variation, that.variation) - && Objects.equals(extraLogging, that.extraLogging); + && Objects.equals(flagKey, that.flagKey) + && Objects.equals(subjectKey, that.subjectKey) + && Objects.equals(subjectAttributes, that.subjectAttributes) + && Objects.equals(allocationKey, that.allocationKey) + && Objects.equals(variation, that.variation) + && Objects.equals(extraLogging, that.extraLogging); } @Override public int hashCode() { - return Objects.hash(flagKey, subjectKey, subjectAttributes, allocationKey, variation, extraLogging, doLog); + return Objects.hash( + flagKey, subjectKey, subjectAttributes, allocationKey, variation, extraLogging, doLog); } public String getFlagKey() { @@ -79,7 +90,7 @@ public String getAllocationKey() { return allocationKey; } - public Variation getVariation() { + public IVariation getVariation() { return variation; } diff --git a/src/main/java/cloud/eppo/FlagEvaluator.java b/src/main/java/cloud/eppo/FlagEvaluator.java index 0a2e78f..7c369cd 100644 --- a/src/main/java/cloud/eppo/FlagEvaluator.java +++ b/src/main/java/cloud/eppo/FlagEvaluator.java @@ -5,11 +5,12 @@ import cloud.eppo.api.Attributes; import cloud.eppo.api.EppoValue; -import cloud.eppo.model.ShardRange; -import cloud.eppo.ufc.dto.Allocation; -import cloud.eppo.ufc.dto.FlagConfig; -import cloud.eppo.ufc.dto.Shard; -import cloud.eppo.ufc.dto.Split; +import cloud.eppo.api.IAllocation; +import cloud.eppo.api.IFlagConfig; +import cloud.eppo.api.IShard; +import cloud.eppo.api.IShardRange; +import cloud.eppo.api.ISplit; +import cloud.eppo.api.IVariation; import cloud.eppo.ufc.dto.Variation; import java.util.Date; import java.util.HashMap; @@ -20,26 +21,26 @@ public class FlagEvaluator { public static FlagEvaluationResult evaluateFlag( - FlagConfig flag, + IFlagConfig flag, String flagKey, String subjectKey, Attributes subjectAttributes, boolean isConfigObfuscated) { Date now = new Date(); - Variation variation = null; + IVariation variation = null; String allocationKey = null; Map extraLogging = new HashMap<>(); boolean doLog = false; // If flag is disabled; use an empty list of allocations so that the empty result is returned // Note: this is a safety check; disabled flags should be filtered upstream - List allocationsToConsider = + List allocationsToConsider = flag.isEnabled() && flag.getAllocations() != null - ? flag.getAllocations() + ? new LinkedList<>(flag.getAllocations()) : new LinkedList<>(); - for (Allocation allocation : allocationsToConsider) { + for (IAllocation allocation : allocationsToConsider) { if (allocation.getStartAt() != null && allocation.getStartAt().after(now)) { // Allocation not yet active continue; @@ -66,7 +67,7 @@ public static FlagEvaluationResult evaluateFlag( } // This allocation has matched; find variation - for (Split split : allocation.getSplits()) { + for (ISplit split : allocation.getSplits()) { if (allShardsMatch(split, subjectKey, flag.getTotalShards(), isConfigObfuscated)) { // Variation and extra logging is determined by the relevant split variation = flag.getVariations().get(split.getVariationKey()); @@ -140,13 +141,13 @@ public static FlagEvaluationResult evaluateFlag( } private static boolean allShardsMatch( - Split split, String subjectKey, int totalShards, boolean isObfuscated) { + ISplit split, String subjectKey, int totalShards, boolean isObfuscated) { if (split.getShards() == null || split.getShards().isEmpty()) { // Default to matching if no explicit shards return true; } - for (Shard shard : split.getShards()) { + for (IShard shard : split.getShards()) { if (!matchesShard(shard, subjectKey, totalShards, isObfuscated)) { return false; } @@ -157,14 +158,14 @@ private static boolean allShardsMatch( } private static boolean matchesShard( - Shard shard, String subjectKey, int totalShards, boolean isObfuscated) { + IShard shard, String subjectKey, int totalShards, boolean isObfuscated) { String salt = shard.getSalt(); if (isObfuscated) { salt = base64Decode(salt); } String hashKey = salt + "-" + subjectKey; int assignedShard = getShard(hashKey, totalShards); - for (ShardRange range : shard.getRanges()) { + for (IShardRange range : shard.getRanges()) { if (assignedShard >= range.getStart() && assignedShard < range.getEnd()) { return true; } diff --git a/src/main/java/cloud/eppo/RuleEvaluator.java b/src/main/java/cloud/eppo/RuleEvaluator.java index 5b9a211..90151c6 100644 --- a/src/main/java/cloud/eppo/RuleEvaluator.java +++ b/src/main/java/cloud/eppo/RuleEvaluator.java @@ -5,9 +5,10 @@ import cloud.eppo.api.Attributes; import cloud.eppo.api.EppoValue; +import cloud.eppo.api.IEppoValue; +import cloud.eppo.api.ITargetingCondition; +import cloud.eppo.api.ITargetingRule; import cloud.eppo.ufc.dto.OperatorType; -import cloud.eppo.ufc.dto.TargetingCondition; -import cloud.eppo.ufc.dto.TargetingRule; import com.github.zafarkhaja.semver.Version; import java.util.Collections; import java.util.Map; @@ -16,9 +17,9 @@ public class RuleEvaluator { - public static TargetingRule findMatchingRule( - Attributes subjectAttributes, Set rules, boolean isObfuscated) { - for (TargetingRule rule : rules) { + public static ITargetingRule findMatchingRule( + Attributes subjectAttributes, Set rules, boolean isObfuscated) { + for (ITargetingRule rule : rules) { if (allConditionsMatch(subjectAttributes, rule.getConditions(), isObfuscated)) { return rule; } @@ -27,8 +28,10 @@ public static TargetingRule findMatchingRule( } private static boolean allConditionsMatch( - Attributes subjectAttributes, Set conditions, boolean isObfuscated) { - for (TargetingCondition condition : conditions) { + Attributes subjectAttributes, + Set conditions, + boolean isObfuscated) { + for (ITargetingCondition condition : conditions) { if (!evaluateCondition(subjectAttributes, condition, isObfuscated)) { return false; } @@ -37,10 +40,10 @@ private static boolean allConditionsMatch( } private static boolean evaluateCondition( - Attributes subjectAttributes, TargetingCondition condition, boolean isObfuscated) { - EppoValue conditionValue = condition.getValue(); + Attributes subjectAttributes, ITargetingCondition condition, boolean isObfuscated) { + IEppoValue conditionValue = condition.getValue(); String attributeKey = condition.getAttribute(); - EppoValue attributeValue = null; + IEppoValue attributeValue = null; if (isObfuscated) { // attribute names are hashed for (Map.Entry entry : subjectAttributes.entrySet()) { @@ -187,7 +190,7 @@ private static boolean evaluateCondition( * IN and NOT IN checks are not strongly typed, as the user is only entering in strings Thus we * need to cast the attribute to a string before hashing and checking */ - private static String castAttributeForListComparison(EppoValue attributeValue) { + private static String castAttributeForListComparison(IEppoValue attributeValue) { if (attributeValue.isBoolean()) { return Boolean.valueOf(attributeValue.booleanValue()).toString(); } else if (attributeValue.isNumeric()) { diff --git a/src/main/java/cloud/eppo/api/Configuration.java b/src/main/java/cloud/eppo/api/Configuration.java index 8634a3a..b1203b8 100644 --- a/src/main/java/cloud/eppo/api/Configuration.java +++ b/src/main/java/cloud/eppo/api/Configuration.java @@ -58,9 +58,9 @@ public class Configuration { "{ \"flags\": {}, \"format\": \"SERVER\" }".getBytes(); private static final Logger log = LoggerFactory.getLogger(Configuration.class); - private final Map banditReferences; - private final Map flags; - private final Map bandits; + private final Map banditReferences; + private final Map flags; + private final Map bandits; private final boolean isConfigObfuscated; @SuppressWarnings("unused") @@ -70,9 +70,9 @@ public class Configuration { /** Default visibility for tests. */ Configuration( - Map flags, - Map banditReferences, - Map bandits, + Map flags, + Map banditReferences, + Map bandits, boolean isConfigObfuscated, byte[] flagConfigJson, byte[] banditParamsJson) { @@ -111,14 +111,20 @@ public static Configuration emptyConfig() { @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 + + ", flagConfigJson=" + + Arrays.toString(flagConfigJson) + + ", banditParamsJson=" + + Arrays.toString(banditParamsJson) + + '}'; } @Override @@ -126,19 +132,25 @@ 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.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, + Arrays.hashCode(flagConfigJson), + Arrays.hashCode(banditParamsJson)); } - public FlagConfig getFlag(String flagKey) { + public IFlagConfig getFlag(String flagKey) { String flagKeyForLookup = flagKey; if (isConfigObfuscated()) { flagKeyForLookup = getMD5Hex(flagKey); @@ -159,7 +171,7 @@ public FlagConfig getFlag(String flagKey) { * @return The flag's variation type or null. */ public @Nullable VariationType getFlagType(String flagKey) { - FlagConfig flag = getFlag(flagKey); + IFlagConfig flag = getFlag(flagKey); if (flag == null) { return null; } @@ -169,9 +181,9 @@ public FlagConfig getFlag(String flagKey) { public String banditKeyForVariation(String flagKey, String variationValue) { // Note: In practice this double loop should be quite quick as the number of bandits and bandit // variations will be small. Should this ever change, we can optimize things. - for (Map.Entry banditEntry : banditReferences.entrySet()) { - BanditReference banditReference = banditEntry.getValue(); - for (BanditFlagVariation banditFlagVariation : banditReference.getFlagVariations()) { + for (Map.Entry banditEntry : banditReferences.entrySet()) { + IBanditReference banditReference = banditEntry.getValue(); + for (IBanditFlagVariation banditFlagVariation : banditReference.getFlagVariations()) { if (banditFlagVariation.getFlagKey().equals(flagKey) && banditFlagVariation.getVariationValue().equals(variationValue)) { return banditEntry.getKey(); @@ -181,7 +193,7 @@ public String banditKeyForVariation(String flagKey, String variationValue) { return null; } - public BanditParameters getBanditParameters(String banditKey) { + public IBanditParameters getBanditParameters(String banditKey) { return bandits.get(banditKey); } @@ -221,18 +233,18 @@ public static Builder builder(byte[] flagJson, boolean isConfigObfuscated) { public static class Builder { private final boolean isConfigObfuscated; - private final Map flags; - private final Map banditReferences; - private Map bandits = Collections.emptyMap(); + private final Map flags; + private final Map banditReferences; + private Map bandits = Collections.emptyMap(); private final byte[] flagJson; private byte[] banditParamsJson; - private static FlagConfigResponse parseFlagResponse(byte[] flagJson) { + private static IFlagConfigResponse parseFlagResponse(byte[] flagJson) { if (flagJson == null || flagJson.length == 0) { log.warn("Null or empty configuration string. Call `Configuration.Empty()` instead"); return null; } - FlagConfigResponse config; + IFlagConfigResponse config; try { return mapper.readValue(flagJson, FlagConfigResponse.class); } catch (IOException e) { @@ -250,11 +262,11 @@ public Builder(byte[] flagJson, boolean isConfigObfuscated) { this(flagJson, parseFlagResponse(flagJson), isConfigObfuscated); } - public Builder(byte[] flagJson, FlagConfigResponse flagConfigResponse) { + public Builder(byte[] flagJson, IFlagConfigResponse flagConfigResponse) { this( flagJson, flagConfigResponse, - flagConfigResponse.getFormat() == FlagConfigResponse.Format.CLIENT); + flagConfigResponse.getFormat() == IFlagConfigResponse.Format.CLIENT); } /** Use this constructor when the FlagConfigResponse has the `forServer` field populated. */ @@ -264,7 +276,7 @@ public Builder(byte[] flagJson) { public Builder( byte[] flagJson, - @Nullable FlagConfigResponse flagConfigResponse, + @Nullable IFlagConfigResponse flagConfigResponse, boolean isConfigObfuscated) { this.isConfigObfuscated = isConfigObfuscated; this.flagJson = flagJson; @@ -287,14 +299,12 @@ public boolean requiresUpdatedBanditModels() { } public Set loadedBanditModelVersions() { - return bandits.values().stream() - .map(BanditParameters::getModelVersion) - .collect(Collectors.toSet()); + return bandits.values().stream().map(b -> b.getModelVersion()).collect(Collectors.toSet()); } public Set referencedBanditModelVersion() { return banditReferences.values().stream() - .map(BanditReference::getModelVersion) + .map(b -> b.getModelVersion()) .collect(Collectors.toSet()); } @@ -317,7 +327,7 @@ public Builder banditParameters(byte[] banditParameterJson) { log.debug("Bandit parameters are null or empty"); return this; } - BanditParametersResponse config; + IBanditParametersResponse config; try { config = mapper.readValue(banditParameterJson, BanditParametersResponse.class); } catch (IOException e) { diff --git a/src/main/java/cloud/eppo/api/EppoValue.java b/src/main/java/cloud/eppo/api/EppoValue.java index aee8bae..560eb74 100644 --- a/src/main/java/cloud/eppo/api/EppoValue.java +++ b/src/main/java/cloud/eppo/api/EppoValue.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.Objects; -public class EppoValue { +public class EppoValue implements IEppoValue { protected final EppoValueType type; protected Boolean boolValue; protected Double doubleValue; diff --git a/src/main/java/cloud/eppo/api/IAllocation.java b/src/main/java/cloud/eppo/api/IAllocation.java new file mode 100644 index 0000000..c040665 --- /dev/null +++ b/src/main/java/cloud/eppo/api/IAllocation.java @@ -0,0 +1,20 @@ +package cloud.eppo.api; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** Interface for Allocation allowing downstream SDKs to provide custom implementations. */ +public interface IAllocation { + String getKey(); + + Set getRules(); + + Date getStartAt(); + + Date getEndAt(); + + List getSplits(); + + boolean doLog(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditAttributeCoefficients.java b/src/main/java/cloud/eppo/api/IBanditAttributeCoefficients.java new file mode 100644 index 0000000..af3ea2e --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditAttributeCoefficients.java @@ -0,0 +1,11 @@ +package cloud.eppo.api; + +/** + * Interface for BanditAttributeCoefficients allowing downstream SDKs to provide custom + * implementations. + */ +public interface IBanditAttributeCoefficients { + String getAttributeKey(); + + double scoreForAttributeValue(IEppoValue attributeValue); +} diff --git a/src/main/java/cloud/eppo/api/IBanditCategoricalAttributeCoefficients.java b/src/main/java/cloud/eppo/api/IBanditCategoricalAttributeCoefficients.java new file mode 100644 index 0000000..7aae693 --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditCategoricalAttributeCoefficients.java @@ -0,0 +1,13 @@ +package cloud.eppo.api; + +import java.util.Map; + +/** + * Interface for BanditCategoricalAttributeCoefficients allowing downstream SDKs to provide custom + * implementations. + */ +public interface IBanditCategoricalAttributeCoefficients extends IBanditAttributeCoefficients { + Double getMissingValueCoefficient(); + + Map getValueCoefficients(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditCoefficients.java b/src/main/java/cloud/eppo/api/IBanditCoefficients.java new file mode 100644 index 0000000..755d6dd --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditCoefficients.java @@ -0,0 +1,19 @@ +package cloud.eppo.api; + +import java.util.Map; + +/** Interface for BanditCoefficients allowing downstream SDKs to provide custom implementations. */ +public interface IBanditCoefficients { + String getActionKey(); + + Double getIntercept(); + + Map getSubjectNumericCoefficients(); + + Map + getSubjectCategoricalCoefficients(); + + Map getActionNumericCoefficients(); + + Map getActionCategoricalCoefficients(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditFlagVariation.java b/src/main/java/cloud/eppo/api/IBanditFlagVariation.java new file mode 100644 index 0000000..ec61cc1 --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditFlagVariation.java @@ -0,0 +1,14 @@ +package cloud.eppo.api; + +/** Interface for BanditFlagVariation allowing downstream SDKs to provide custom implementations. */ +public interface IBanditFlagVariation { + String getBanditKey(); + + String getFlagKey(); + + String getAllocationKey(); + + String getVariationKey(); + + String getVariationValue(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditModelData.java b/src/main/java/cloud/eppo/api/IBanditModelData.java new file mode 100644 index 0000000..6f21b3c --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditModelData.java @@ -0,0 +1,14 @@ +package cloud.eppo.api; + +import java.util.Map; + +/** Interface for BanditModelData allowing downstream SDKs to provide custom implementations. */ +public interface IBanditModelData { + Double getGamma(); + + Double getDefaultActionScore(); + + Double getActionProbabilityFloor(); + + Map getCoefficients(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditNumericAttributeCoefficients.java b/src/main/java/cloud/eppo/api/IBanditNumericAttributeCoefficients.java new file mode 100644 index 0000000..b28d76c --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditNumericAttributeCoefficients.java @@ -0,0 +1,11 @@ +package cloud.eppo.api; + +/** + * Interface for BanditNumericAttributeCoefficients allowing downstream SDKs to provide custom + * implementations. + */ +public interface IBanditNumericAttributeCoefficients extends IBanditAttributeCoefficients { + Double getCoefficient(); + + Double getMissingValueCoefficient(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditParameters.java b/src/main/java/cloud/eppo/api/IBanditParameters.java new file mode 100644 index 0000000..6413c11 --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditParameters.java @@ -0,0 +1,16 @@ +package cloud.eppo.api; + +import java.util.Date; + +/** Interface for BanditParameters allowing downstream SDKs to provide custom implementations. */ +public interface IBanditParameters { + String getBanditKey(); + + Date getUpdatedAt(); + + String getModelName(); + + String getModelVersion(); + + IBanditModelData getModelData(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditParametersResponse.java b/src/main/java/cloud/eppo/api/IBanditParametersResponse.java new file mode 100644 index 0000000..530016f --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditParametersResponse.java @@ -0,0 +1,11 @@ +package cloud.eppo.api; + +import java.util.Map; + +/** + * Interface for BanditParametersResponse allowing downstream SDKs to provide custom + * implementations. + */ +public interface IBanditParametersResponse { + Map getBandits(); +} diff --git a/src/main/java/cloud/eppo/api/IBanditReference.java b/src/main/java/cloud/eppo/api/IBanditReference.java new file mode 100644 index 0000000..539a1ce --- /dev/null +++ b/src/main/java/cloud/eppo/api/IBanditReference.java @@ -0,0 +1,10 @@ +package cloud.eppo.api; + +import java.util.List; + +/** Interface for BanditReference allowing downstream SDKs to provide custom implementations. */ +public interface IBanditReference { + String getModelVersion(); + + List getFlagVariations(); +} diff --git a/src/main/java/cloud/eppo/api/IEppoValue.java b/src/main/java/cloud/eppo/api/IEppoValue.java new file mode 100644 index 0000000..681812d --- /dev/null +++ b/src/main/java/cloud/eppo/api/IEppoValue.java @@ -0,0 +1,27 @@ +package cloud.eppo.api; + +import cloud.eppo.ufc.dto.EppoValueType; +import java.util.List; + +/** Interface for EppoValue allowing downstream SDKs to provide custom implementations. */ +public interface IEppoValue { + boolean booleanValue(); + + double doubleValue(); + + String stringValue(); + + List stringArrayValue(); + + boolean isNull(); + + boolean isBoolean(); + + boolean isNumeric(); + + boolean isString(); + + boolean isStringArray(); + + EppoValueType getType(); +} diff --git a/src/main/java/cloud/eppo/api/IFlagConfig.java b/src/main/java/cloud/eppo/api/IFlagConfig.java new file mode 100644 index 0000000..70ae228 --- /dev/null +++ b/src/main/java/cloud/eppo/api/IFlagConfig.java @@ -0,0 +1,20 @@ +package cloud.eppo.api; + +import cloud.eppo.ufc.dto.VariationType; +import java.util.List; +import java.util.Map; + +/** Interface for FlagConfig allowing downstream SDKs to provide custom implementations. */ +public interface IFlagConfig { + String getKey(); + + boolean isEnabled(); + + int getTotalShards(); + + VariationType getVariationType(); + + Map getVariations(); + + List getAllocations(); +} diff --git a/src/main/java/cloud/eppo/api/IFlagConfigResponse.java b/src/main/java/cloud/eppo/api/IFlagConfigResponse.java new file mode 100644 index 0000000..6154bba --- /dev/null +++ b/src/main/java/cloud/eppo/api/IFlagConfigResponse.java @@ -0,0 +1,17 @@ +package cloud.eppo.api; + +import java.util.Map; + +/** Interface for FlagConfigResponse allowing downstream SDKs to provide custom implementations. */ +public interface IFlagConfigResponse { + Map getFlags(); + + Map getBanditReferences(); + + Format getFormat(); + + enum Format { + SERVER, + CLIENT + } +} diff --git a/src/main/java/cloud/eppo/api/IShard.java b/src/main/java/cloud/eppo/api/IShard.java new file mode 100644 index 0000000..4f2249d --- /dev/null +++ b/src/main/java/cloud/eppo/api/IShard.java @@ -0,0 +1,10 @@ +package cloud.eppo.api; + +import java.util.Set; + +/** Interface for Shard allowing downstream SDKs to provide custom implementations. */ +public interface IShard { + String getSalt(); + + Set getRanges(); +} diff --git a/src/main/java/cloud/eppo/api/IShardRange.java b/src/main/java/cloud/eppo/api/IShardRange.java new file mode 100644 index 0000000..4fb1fb8 --- /dev/null +++ b/src/main/java/cloud/eppo/api/IShardRange.java @@ -0,0 +1,8 @@ +package cloud.eppo.api; + +/** Interface for ShardRange allowing downstream SDKs to provide custom implementations. */ +public interface IShardRange { + int getStart(); + + int getEnd(); +} diff --git a/src/main/java/cloud/eppo/api/ISplit.java b/src/main/java/cloud/eppo/api/ISplit.java new file mode 100644 index 0000000..52e11fd --- /dev/null +++ b/src/main/java/cloud/eppo/api/ISplit.java @@ -0,0 +1,13 @@ +package cloud.eppo.api; + +import java.util.Map; +import java.util.Set; + +/** Interface for Split allowing downstream SDKs to provide custom implementations. */ +public interface ISplit { + String getVariationKey(); + + Set getShards(); + + Map getExtraLogging(); +} diff --git a/src/main/java/cloud/eppo/api/ITargetingCondition.java b/src/main/java/cloud/eppo/api/ITargetingCondition.java new file mode 100644 index 0000000..ca4a726 --- /dev/null +++ b/src/main/java/cloud/eppo/api/ITargetingCondition.java @@ -0,0 +1,12 @@ +package cloud.eppo.api; + +import cloud.eppo.ufc.dto.OperatorType; + +/** Interface for TargetingCondition allowing downstream SDKs to provide custom implementations. */ +public interface ITargetingCondition { + OperatorType getOperator(); + + String getAttribute(); + + IEppoValue getValue(); +} diff --git a/src/main/java/cloud/eppo/api/ITargetingRule.java b/src/main/java/cloud/eppo/api/ITargetingRule.java new file mode 100644 index 0000000..43c3d98 --- /dev/null +++ b/src/main/java/cloud/eppo/api/ITargetingRule.java @@ -0,0 +1,8 @@ +package cloud.eppo.api; + +import java.util.Set; + +/** Interface for TargetingRule allowing downstream SDKs to provide custom implementations. */ +public interface ITargetingRule { + Set getConditions(); +} diff --git a/src/main/java/cloud/eppo/api/IVariation.java b/src/main/java/cloud/eppo/api/IVariation.java new file mode 100644 index 0000000..1e5f6f7 --- /dev/null +++ b/src/main/java/cloud/eppo/api/IVariation.java @@ -0,0 +1,8 @@ +package cloud.eppo.api; + +/** Interface for Variation allowing downstream SDKs to provide custom implementations. */ +public interface IVariation { + String getKey(); + + IEppoValue getValue(); +} diff --git a/src/main/java/cloud/eppo/model/ShardRange.java b/src/main/java/cloud/eppo/model/ShardRange.java index c93e6f3..0fcdf50 100644 --- a/src/main/java/cloud/eppo/model/ShardRange.java +++ b/src/main/java/cloud/eppo/model/ShardRange.java @@ -1,12 +1,12 @@ package cloud.eppo.model; +import cloud.eppo.api.IShardRange; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.Objects; /** Shard Range Class */ -public class ShardRange { +public class ShardRange implements IShardRange { private final int start; private int end; @@ -20,8 +20,7 @@ public ShardRange(@JsonProperty("start") int start, @JsonProperty("end") int end public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; ShardRange that = (ShardRange) o; - return start == that.start && - end == that.end; + return start == that.start && end == that.end; } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/Allocation.java b/src/main/java/cloud/eppo/ufc/dto/Allocation.java index 075dba4..ba41b4c 100644 --- a/src/main/java/cloud/eppo/ufc/dto/Allocation.java +++ b/src/main/java/cloud/eppo/ufc/dto/Allocation.java @@ -1,11 +1,12 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IAllocation; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Set; -public class Allocation { +public class Allocation implements IAllocation { private String key; private Set rules; private Date startAt; @@ -30,14 +31,21 @@ public Allocation( @Override public String toString() { - return "Allocation{" + - "key='" + key + '\'' + - ", rules=" + rules + - ", startAt=" + startAt + - ", endAt=" + endAt + - ", splits=" + splits + - ", doLog=" + doLog + - '}'; + return "Allocation{" + + "key='" + + key + + '\'' + + ", rules=" + + rules + + ", startAt=" + + startAt + + ", endAt=" + + endAt + + ", splits=" + + splits + + ", doLog=" + + doLog + + '}'; } @Override @@ -45,11 +53,11 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Allocation that = (Allocation) o; return doLog == that.doLog - && Objects.equals(key, that.key) - && Objects.equals(rules, that.rules) - && Objects.equals(startAt, that.startAt) - && Objects.equals(endAt, that.endAt) - && Objects.equals(splits, that.splits); + && Objects.equals(key, that.key) + && Objects.equals(rules, that.rules) + && Objects.equals(startAt, that.startAt) + && Objects.equals(endAt, that.endAt) + && Objects.equals(splits, that.splits); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditAttributeCoefficients.java b/src/main/java/cloud/eppo/ufc/dto/BanditAttributeCoefficients.java index 2a0bb9b..3c7d2c5 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditAttributeCoefficients.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditAttributeCoefficients.java @@ -1,10 +1,11 @@ package cloud.eppo.ufc.dto; -import cloud.eppo.api.EppoValue; +import cloud.eppo.api.IBanditAttributeCoefficients; +import cloud.eppo.api.IEppoValue; -public interface BanditAttributeCoefficients { +public interface BanditAttributeCoefficients extends IBanditAttributeCoefficients { String getAttributeKey(); - double scoreForAttributeValue(EppoValue attributeValue); + double scoreForAttributeValue(IEppoValue attributeValue); } diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditCategoricalAttributeCoefficients.java b/src/main/java/cloud/eppo/ufc/dto/BanditCategoricalAttributeCoefficients.java index 05e7055..3fa09ac 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditCategoricalAttributeCoefficients.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditCategoricalAttributeCoefficients.java @@ -1,13 +1,13 @@ package cloud.eppo.ufc.dto; -import cloud.eppo.api.EppoValue; +import cloud.eppo.api.IBanditCategoricalAttributeCoefficients; import java.util.Map; import java.util.Objects; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BanditCategoricalAttributeCoefficients implements BanditAttributeCoefficients { +public class BanditCategoricalAttributeCoefficients + implements BanditAttributeCoefficients, IBanditCategoricalAttributeCoefficients { private final Logger logger = LoggerFactory.getLogger(BanditCategoricalAttributeCoefficients.class); private final String attributeKey; @@ -23,11 +23,15 @@ public BanditCategoricalAttributeCoefficients( @Override public String toString() { - return "BanditCategoricalAttributeCoefficients{" + - "attributeKey='" + attributeKey + '\'' + - ", missingValueCoefficient=" + missingValueCoefficient + - ", valueCoefficients=" + valueCoefficients + - '}'; + return "BanditCategoricalAttributeCoefficients{" + + "attributeKey='" + + attributeKey + + '\'' + + ", missingValueCoefficient=" + + missingValueCoefficient + + ", valueCoefficients=" + + valueCoefficients + + '}'; } @Override @@ -35,9 +39,9 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BanditCategoricalAttributeCoefficients that = (BanditCategoricalAttributeCoefficients) o; return Objects.equals(logger, that.logger) - && Objects.equals(attributeKey, that.attributeKey) - && Objects.equals(missingValueCoefficient, that.missingValueCoefficient) - && Objects.equals(valueCoefficients, that.valueCoefficients); + && Objects.equals(attributeKey, that.attributeKey) + && Objects.equals(missingValueCoefficient, that.missingValueCoefficient) + && Objects.equals(valueCoefficients, that.valueCoefficients); } @Override @@ -50,7 +54,7 @@ public String getAttributeKey() { return attributeKey; } - public double scoreForAttributeValue(EppoValue attributeValue) { + public double scoreForAttributeValue(cloud.eppo.api.IEppoValue attributeValue) { if (attributeValue == null || attributeValue.isNull()) { return missingValueCoefficient; } diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditCoefficients.java b/src/main/java/cloud/eppo/ufc/dto/BanditCoefficients.java index f957a8d..469d68b 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditCoefficients.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditCoefficients.java @@ -1,9 +1,10 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IBanditCoefficients; import java.util.Map; import java.util.Objects; -public class BanditCoefficients { +public class BanditCoefficients implements IBanditCoefficients { private final String actionKey; private final Double intercept; private final Map subjectNumericCoefficients; @@ -28,14 +29,21 @@ public BanditCoefficients( @Override public String toString() { - return "BanditCoefficients{" + - "actionKey='" + actionKey + '\'' + - ", intercept=" + intercept + - ", subjectNumericCoefficients=" + subjectNumericCoefficients + - ", subjectCategoricalCoefficients=" + subjectCategoricalCoefficients + - ", actionNumericCoefficients=" + actionNumericCoefficients + - ", actionCategoricalCoefficients=" + actionCategoricalCoefficients + - '}'; + return "BanditCoefficients{" + + "actionKey='" + + actionKey + + '\'' + + ", intercept=" + + intercept + + ", subjectNumericCoefficients=" + + subjectNumericCoefficients + + ", subjectCategoricalCoefficients=" + + subjectCategoricalCoefficients + + ", actionNumericCoefficients=" + + actionNumericCoefficients + + ", actionCategoricalCoefficients=" + + actionCategoricalCoefficients + + '}'; } @Override @@ -43,16 +51,22 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BanditCoefficients that = (BanditCoefficients) o; return Objects.equals(actionKey, that.actionKey) - && Objects.equals(intercept, that.intercept) - && Objects.equals(subjectNumericCoefficients, that.subjectNumericCoefficients) - && Objects.equals(subjectCategoricalCoefficients, that.subjectCategoricalCoefficients) - && Objects.equals(actionNumericCoefficients, that.actionNumericCoefficients) - && Objects.equals(actionCategoricalCoefficients, that.actionCategoricalCoefficients); + && Objects.equals(intercept, that.intercept) + && Objects.equals(subjectNumericCoefficients, that.subjectNumericCoefficients) + && Objects.equals(subjectCategoricalCoefficients, that.subjectCategoricalCoefficients) + && Objects.equals(actionNumericCoefficients, that.actionNumericCoefficients) + && Objects.equals(actionCategoricalCoefficients, that.actionCategoricalCoefficients); } @Override public int hashCode() { - return Objects.hash(actionKey, intercept, subjectNumericCoefficients, subjectCategoricalCoefficients, actionNumericCoefficients, actionCategoricalCoefficients); + return Objects.hash( + actionKey, + intercept, + subjectNumericCoefficients, + subjectCategoricalCoefficients, + actionNumericCoefficients, + actionCategoricalCoefficients); } public String getActionKey() { diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditFlagVariation.java b/src/main/java/cloud/eppo/ufc/dto/BanditFlagVariation.java index 8298233..24792bd 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditFlagVariation.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditFlagVariation.java @@ -1,8 +1,9 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IBanditFlagVariation; import java.util.Objects; -public class BanditFlagVariation { +public class BanditFlagVariation implements IBanditFlagVariation { private final String banditKey; private final String flagKey; private final String allocationKey; @@ -24,13 +25,23 @@ public BanditFlagVariation( @Override public String toString() { - return "BanditFlagVariation{" + - "banditKey='" + banditKey + '\'' + - ", flagKey='" + flagKey + '\'' + - ", allocationKey='" + allocationKey + '\'' + - ", variationKey='" + variationKey + '\'' + - ", variationValue='" + variationValue + '\'' + - '}'; + return "BanditFlagVariation{" + + "banditKey='" + + banditKey + + '\'' + + ", flagKey='" + + flagKey + + '\'' + + ", allocationKey='" + + allocationKey + + '\'' + + ", variationKey='" + + variationKey + + '\'' + + ", variationValue='" + + variationValue + + '\'' + + '}'; } @Override @@ -38,10 +49,10 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BanditFlagVariation that = (BanditFlagVariation) o; return Objects.equals(banditKey, that.banditKey) - && Objects.equals(flagKey, that.flagKey) - && Objects.equals(allocationKey, that.allocationKey) - && Objects.equals(variationKey, that.variationKey) - && Objects.equals(variationValue, that.variationValue); + && Objects.equals(flagKey, that.flagKey) + && Objects.equals(allocationKey, that.allocationKey) + && Objects.equals(variationKey, that.variationKey) + && Objects.equals(variationValue, that.variationValue); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditModelData.java b/src/main/java/cloud/eppo/ufc/dto/BanditModelData.java index b2ef42f..bd18898 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditModelData.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditModelData.java @@ -1,9 +1,10 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IBanditModelData; import java.util.Map; import java.util.Objects; -public class BanditModelData { +public class BanditModelData implements IBanditModelData { private final Double gamma; private final Double defaultActionScore; private final Double actionProbabilityFloor; @@ -22,12 +23,16 @@ public BanditModelData( @Override public String toString() { - return "BanditModelData{" + - "gamma=" + gamma + - ", defaultActionScore=" + defaultActionScore + - ", actionProbabilityFloor=" + actionProbabilityFloor + - ", coefficients=" + coefficients + - '}'; + return "BanditModelData{" + + "gamma=" + + gamma + + ", defaultActionScore=" + + defaultActionScore + + ", actionProbabilityFloor=" + + actionProbabilityFloor + + ", coefficients=" + + coefficients + + '}'; } @Override @@ -35,9 +40,9 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BanditModelData that = (BanditModelData) o; return Objects.equals(gamma, that.gamma) - && Objects.equals(defaultActionScore, that.defaultActionScore) - && Objects.equals(actionProbabilityFloor, that.actionProbabilityFloor) - && Objects.equals(coefficients, that.coefficients); + && Objects.equals(defaultActionScore, that.defaultActionScore) + && Objects.equals(actionProbabilityFloor, that.actionProbabilityFloor) + && Objects.equals(coefficients, that.coefficients); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditNumericAttributeCoefficients.java b/src/main/java/cloud/eppo/ufc/dto/BanditNumericAttributeCoefficients.java index 412e384..0a76a00 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditNumericAttributeCoefficients.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditNumericAttributeCoefficients.java @@ -1,12 +1,12 @@ package cloud.eppo.ufc.dto; -import cloud.eppo.api.EppoValue; +import cloud.eppo.api.IBanditNumericAttributeCoefficients; +import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Objects; - -public class BanditNumericAttributeCoefficients implements BanditAttributeCoefficients { +public class BanditNumericAttributeCoefficients + implements BanditAttributeCoefficients, IBanditNumericAttributeCoefficients { private final Logger logger = LoggerFactory.getLogger(BanditNumericAttributeCoefficients.class); private final String attributeKey; private final Double coefficient; @@ -21,11 +21,15 @@ public BanditNumericAttributeCoefficients( @Override public String toString() { - return "BanditNumericAttributeCoefficients{" + - "attributeKey='" + attributeKey + '\'' + - ", coefficient=" + coefficient + - ", missingValueCoefficient=" + missingValueCoefficient + - '}'; + return "BanditNumericAttributeCoefficients{" + + "attributeKey='" + + attributeKey + + '\'' + + ", coefficient=" + + coefficient + + ", missingValueCoefficient=" + + missingValueCoefficient + + '}'; } @Override @@ -33,9 +37,9 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BanditNumericAttributeCoefficients that = (BanditNumericAttributeCoefficients) o; return Objects.equals(logger, that.logger) - && Objects.equals(attributeKey, that.attributeKey) - && Objects.equals(coefficient, that.coefficient) - && Objects.equals(missingValueCoefficient, that.missingValueCoefficient); + && Objects.equals(attributeKey, that.attributeKey) + && Objects.equals(coefficient, that.coefficient) + && Objects.equals(missingValueCoefficient, that.missingValueCoefficient); } @Override @@ -49,7 +53,7 @@ public String getAttributeKey() { } @Override - public double scoreForAttributeValue(EppoValue attributeValue) { + public double scoreForAttributeValue(cloud.eppo.api.IEppoValue attributeValue) { if (attributeValue == null || attributeValue.isNull()) { return missingValueCoefficient; } diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditParameters.java b/src/main/java/cloud/eppo/ufc/dto/BanditParameters.java index ddfd625..db7c8d0 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditParameters.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditParameters.java @@ -1,9 +1,10 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IBanditParameters; import java.util.Date; import java.util.Objects; -public class BanditParameters { +public class BanditParameters implements IBanditParameters { private final String banditKey; private final Date updatedAt; private final String modelName; @@ -25,13 +26,21 @@ public BanditParameters( @Override public String toString() { - return "BanditParameters{" + - "banditKey='" + banditKey + '\'' + - ", updatedAt=" + updatedAt + - ", modelName='" + modelName + '\'' + - ", modelVersion='" + modelVersion + '\'' + - ", modelData=" + modelData + - '}'; + return "BanditParameters{" + + "banditKey='" + + banditKey + + '\'' + + ", updatedAt=" + + updatedAt + + ", modelName='" + + modelName + + '\'' + + ", modelVersion='" + + modelVersion + + '\'' + + ", modelData=" + + modelData + + '}'; } @Override @@ -39,10 +48,10 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BanditParameters that = (BanditParameters) o; return Objects.equals(banditKey, that.banditKey) - && Objects.equals(updatedAt, that.updatedAt) - && Objects.equals(modelName, that.modelName) - && Objects.equals(modelVersion, that.modelVersion) - && Objects.equals(modelData, that.modelData); + && Objects.equals(updatedAt, that.updatedAt) + && Objects.equals(modelName, that.modelName) + && Objects.equals(modelVersion, that.modelVersion) + && Objects.equals(modelData, that.modelData); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditParametersResponse.java b/src/main/java/cloud/eppo/ufc/dto/BanditParametersResponse.java index 3b0fde2..42aa382 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditParametersResponse.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditParametersResponse.java @@ -1,10 +1,11 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IBanditParametersResponse; import java.util.HashMap; import java.util.Map; import java.util.Objects; -public class BanditParametersResponse { +public class BanditParametersResponse implements IBanditParametersResponse { private final Map bandits; @@ -18,9 +19,7 @@ public BanditParametersResponse(Map bandits) { @Override public String toString() { - return "BanditParametersResponse{" + - "bandits=" + bandits + - '}'; + return "BanditParametersResponse{" + "bandits=" + bandits + '}'; } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/BanditReference.java b/src/main/java/cloud/eppo/ufc/dto/BanditReference.java index 1ec490a..13880d9 100644 --- a/src/main/java/cloud/eppo/ufc/dto/BanditReference.java +++ b/src/main/java/cloud/eppo/ufc/dto/BanditReference.java @@ -1,9 +1,10 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IBanditReference; import java.util.List; import java.util.Objects; -public class BanditReference { +public class BanditReference implements IBanditReference { private final String modelVersion; private final List flagVariations; @@ -14,10 +15,13 @@ public BanditReference(String modelVersion, List flagVariat @Override public String toString() { - return "BanditReference{" + - "modelVersion='" + modelVersion + '\'' + - ", flagVariations=" + flagVariations + - '}'; + return "BanditReference{" + + "modelVersion='" + + modelVersion + + '\'' + + ", flagVariations=" + + flagVariations + + '}'; } @Override @@ -25,7 +29,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BanditReference that = (BanditReference) o; return Objects.equals(modelVersion, that.modelVersion) - && Objects.equals(flagVariations, that.flagVariations); + && Objects.equals(flagVariations, that.flagVariations); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/FlagConfig.java b/src/main/java/cloud/eppo/ufc/dto/FlagConfig.java index 521a509..e2463cd 100644 --- a/src/main/java/cloud/eppo/ufc/dto/FlagConfig.java +++ b/src/main/java/cloud/eppo/ufc/dto/FlagConfig.java @@ -1,10 +1,11 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IFlagConfig; import java.util.List; import java.util.Map; import java.util.Objects; -public class FlagConfig { +public class FlagConfig implements IFlagConfig { private final String key; private final boolean enabled; private final int totalShards; @@ -29,14 +30,21 @@ public FlagConfig( @Override public String toString() { - return "FlagConfig{" + - "key='" + key + '\'' + - ", enabled=" + enabled + - ", totalShards=" + totalShards + - ", variationType=" + variationType + - ", variations=" + variations + - ", allocations=" + allocations + - '}'; + return "FlagConfig{" + + "key='" + + key + + '\'' + + ", enabled=" + + enabled + + ", totalShards=" + + totalShards + + ", variationType=" + + variationType + + ", variations=" + + variations + + ", allocations=" + + allocations + + '}'; } @Override @@ -44,11 +52,11 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; FlagConfig that = (FlagConfig) o; return enabled == that.enabled - && totalShards == that.totalShards - && Objects.equals(key, that.key) - && variationType == that.variationType - && Objects.equals(variations, that.variations) - && Objects.equals(allocations, that.allocations); + && totalShards == that.totalShards + && Objects.equals(key, that.key) + && variationType == that.variationType + && Objects.equals(variations, that.variations) + && Objects.equals(allocations, that.allocations); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/FlagConfigResponse.java b/src/main/java/cloud/eppo/ufc/dto/FlagConfigResponse.java index cb9e35b..6a01835 100644 --- a/src/main/java/cloud/eppo/ufc/dto/FlagConfigResponse.java +++ b/src/main/java/cloud/eppo/ufc/dto/FlagConfigResponse.java @@ -1,18 +1,19 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IFlagConfigResponse; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -public class FlagConfigResponse { +public class FlagConfigResponse implements IFlagConfigResponse { private final Map flags; private final Map banditReferences; - private final Format format; + private final IFlagConfigResponse.Format format; public FlagConfigResponse( Map flags, Map banditReferences, - Format dataFormat) { + IFlagConfigResponse.Format dataFormat) { this.flags = flags; this.banditReferences = banditReferences; format = dataFormat; @@ -20,20 +21,23 @@ public FlagConfigResponse( public FlagConfigResponse( Map flags, Map banditReferences) { - this(flags, banditReferences, Format.SERVER); + this(flags, banditReferences, IFlagConfigResponse.Format.SERVER); } public FlagConfigResponse() { - this(new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), Format.SERVER); + this(new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), IFlagConfigResponse.Format.SERVER); } @Override public String toString() { - return "FlagConfigResponse{" + - "flags=" + flags + - ", banditReferences=" + banditReferences + - ", format=" + format + - '}'; + return "FlagConfigResponse{" + + "flags=" + + flags + + ", banditReferences=" + + banditReferences + + ", format=" + + format + + '}'; } @Override @@ -41,8 +45,8 @@ 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; } @Override @@ -58,12 +62,8 @@ public Map getBanditReferences() { return this.banditReferences; } - public Format getFormat() { + @Override + public IFlagConfigResponse.Format getFormat() { return format; } - - public enum Format { - SERVER, - CLIENT - } } diff --git a/src/main/java/cloud/eppo/ufc/dto/Shard.java b/src/main/java/cloud/eppo/ufc/dto/Shard.java index 0dba161..959f3a0 100644 --- a/src/main/java/cloud/eppo/ufc/dto/Shard.java +++ b/src/main/java/cloud/eppo/ufc/dto/Shard.java @@ -1,11 +1,11 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.IShard; import cloud.eppo.model.ShardRange; - import java.util.Objects; import java.util.Set; -public class Shard { +public class Shard implements IShard { private final String salt; private final Set ranges; @@ -16,18 +16,14 @@ public Shard(String salt, Set ranges) { @Override public String toString() { - return "Shard{" + - "salt='" + salt + '\'' + - ", ranges=" + ranges + - '}'; + return "Shard{" + "salt='" + salt + '\'' + ", ranges=" + ranges + '}'; } @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Shard shard = (Shard) o; - return Objects.equals(salt, shard.salt) - && Objects.equals(ranges, shard.ranges); + return Objects.equals(salt, shard.salt) && Objects.equals(ranges, shard.ranges); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/Split.java b/src/main/java/cloud/eppo/ufc/dto/Split.java index 1dca9ed..33bd9d7 100644 --- a/src/main/java/cloud/eppo/ufc/dto/Split.java +++ b/src/main/java/cloud/eppo/ufc/dto/Split.java @@ -1,10 +1,11 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.ISplit; import java.util.Map; import java.util.Objects; import java.util.Set; -public class Split { +public class Split implements ISplit { private final String variationKey; private final Set shards; private final Map extraLogging; @@ -17,11 +18,15 @@ public Split(String variationKey, Set shards, Map extraLo @Override public String toString() { - return "Split{" + - "variationKey='" + variationKey + '\'' + - ", shards=" + shards + - ", extraLogging=" + extraLogging + - '}'; + return "Split{" + + "variationKey='" + + variationKey + + '\'' + + ", shards=" + + shards + + ", extraLogging=" + + extraLogging + + '}'; } @Override @@ -29,8 +34,8 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Split split = (Split) o; return Objects.equals(variationKey, split.variationKey) - && Objects.equals(shards, split.shards) - && Objects.equals(extraLogging, split.extraLogging); + && Objects.equals(shards, split.shards) + && Objects.equals(extraLogging, split.extraLogging); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/TargetingCondition.java b/src/main/java/cloud/eppo/ufc/dto/TargetingCondition.java index bc84751..cf61086 100644 --- a/src/main/java/cloud/eppo/ufc/dto/TargetingCondition.java +++ b/src/main/java/cloud/eppo/ufc/dto/TargetingCondition.java @@ -1,10 +1,10 @@ package cloud.eppo.ufc.dto; -import java.util.Objects; - import cloud.eppo.api.EppoValue; +import cloud.eppo.api.ITargetingCondition; +import java.util.Objects; -public class TargetingCondition { +public class TargetingCondition implements ITargetingCondition { private final OperatorType operator; private final String attribute; private final EppoValue value; @@ -17,11 +17,15 @@ public TargetingCondition(OperatorType operator, String attribute, EppoValue val @Override public String toString() { - return "TargetingCondition{" + - "operator=" + operator + - ", attribute='" + attribute + '\'' + - ", value=" + value + - '}'; + return "TargetingCondition{" + + "operator=" + + operator + + ", attribute='" + + attribute + + '\'' + + ", value=" + + value + + '}'; } @Override @@ -29,8 +33,8 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; TargetingCondition that = (TargetingCondition) o; return operator == that.operator - && Objects.equals(attribute, that.attribute) - && Objects.equals(value, that.value); + && Objects.equals(attribute, that.attribute) + && Objects.equals(value, that.value); } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/TargetingRule.java b/src/main/java/cloud/eppo/ufc/dto/TargetingRule.java index 7865514..b23ba9b 100644 --- a/src/main/java/cloud/eppo/ufc/dto/TargetingRule.java +++ b/src/main/java/cloud/eppo/ufc/dto/TargetingRule.java @@ -1,9 +1,10 @@ package cloud.eppo.ufc.dto; +import cloud.eppo.api.ITargetingRule; import java.util.Objects; import java.util.Set; -public class TargetingRule { +public class TargetingRule implements ITargetingRule { private final Set conditions; public TargetingRule(Set conditions) { @@ -16,9 +17,7 @@ public Set getConditions() { @Override public String toString() { - return "TargetingRule{" + - "conditions=" + conditions + - '}'; + return "TargetingRule{" + "conditions=" + conditions + '}'; } @Override diff --git a/src/main/java/cloud/eppo/ufc/dto/Variation.java b/src/main/java/cloud/eppo/ufc/dto/Variation.java index 948f62a..09915d6 100644 --- a/src/main/java/cloud/eppo/ufc/dto/Variation.java +++ b/src/main/java/cloud/eppo/ufc/dto/Variation.java @@ -1,10 +1,10 @@ package cloud.eppo.ufc.dto; -import java.util.Objects; - import cloud.eppo.api.EppoValue; +import cloud.eppo.api.IVariation; +import java.util.Objects; -public class Variation { +public class Variation implements IVariation { private final String key; private final EppoValue value; @@ -15,18 +15,14 @@ public Variation(String key, EppoValue value) { @Override public String toString() { - return "Variation{" + - "key='" + key + '\'' + - ", value=" + value + - '}'; + return "Variation{" + "key='" + key + '\'' + ", value=" + value + '}'; } @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Variation variation = (Variation) o; - return Objects.equals(key, variation.key) - && Objects.equals(value, variation.value); + return Objects.equals(key, variation.key) && Objects.equals(value, variation.value); } @Override diff --git a/src/test/java/cloud/eppo/BaseEppoClientTest.java b/src/test/java/cloud/eppo/BaseEppoClientTest.java index 4c80544..dd25367 100644 --- a/src/test/java/cloud/eppo/BaseEppoClientTest.java +++ b/src/test/java/cloud/eppo/BaseEppoClientTest.java @@ -13,7 +13,6 @@ import cloud.eppo.helpers.AssignmentTestCase; import cloud.eppo.logging.Assignment; import cloud.eppo.logging.AssignmentLogger; -import cloud.eppo.ufc.dto.FlagConfig; import cloud.eppo.ufc.dto.VariationType; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -782,7 +781,7 @@ public void testGetConfigurationWithInitialConfig() { assertNotNull(config); // Verify known flag from initial configuration - FlagConfig numericFlag = config.getFlag("numeric_flag"); + cloud.eppo.api.IFlagConfig numericFlag = config.getFlag("numeric_flag"); assertNotNull(numericFlag); assertEquals(VariationType.NUMERIC, numericFlag.getVariationType());