Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "src/test/java/com/flagsmith/flagengine/enginetestdata"]
path = src/test/java/com/flagsmith/flagengine/enginetestdata
url = [email protected]:Flagsmith/engine-test-data.git
tag = v2.5.0
tag = v3.2.1
44 changes: 32 additions & 12 deletions src/main/java/com/flagsmith/flagengine/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import com.flagsmith.flagengine.segments.SegmentEvaluator;
import com.flagsmith.flagengine.utils.Hashing;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;

public class Engine {
public class Engine {
private static class SegmentEvaluationResult {
List<SegmentResult> segments;
HashMap<String, ImmutablePair<String, FeatureContext>> segmentFeatureContexts;
Expand Down Expand Up @@ -35,6 +37,7 @@ public HashMap<String, ImmutablePair<String, FeatureContext>> getSegmentFeatureC
* @return Evaluation result.
*/
public static EvaluationResult getEvaluationResult(EvaluationContext context) {
context = getEnrichedEvaluationContext(context);
SegmentEvaluationResult segmentEvaluationResult = evaluateSegments(context);
Flags flags = evaluateFeatures(context, segmentEvaluationResult.getSegmentFeatureContexts());

Expand All @@ -43,6 +46,24 @@ public static EvaluationResult getEvaluationResult(EvaluationContext context) {
.withSegments(segmentEvaluationResult.getSegments());
}

/*
* Get a version of the evaluation context enriched with derived data.
*
* @param context Evaluation context.
* @return Enriched evaluation context, or the original if no enrichment was needed.
*/
private static EvaluationContext getEnrichedEvaluationContext(EvaluationContext context) {
IdentityContext identity = context.getIdentity();
if (identity != null) {
if (StringUtils.isEmpty(identity.getKey())) {
String identityKey = context.getEnvironment().getKey() + "_" + identity.getIdentifier();
context = new EvaluationContext(context).withIdentity(
new IdentityContext(identity).withKey(identityKey));
}
}
return context;
}

private static SegmentEvaluationResult evaluateSegments(
EvaluationContext context) {
List<SegmentResult> segments = new ArrayList<>();
Expand All @@ -53,19 +74,19 @@ private static SegmentEvaluationResult evaluateSegments(
if (contextSegments != null) {
for (SegmentContext segmentContext : contextSegments.getAdditionalProperties().values()) {
if (SegmentEvaluator.isContextInSegment(context, segmentContext)) {
segments.add(new SegmentResult().withKey(segmentContext.getKey())
segments.add(new SegmentResult()
.withName(segmentContext.getName())
.withMetadata(segmentContext.getMetadata()));

List<FeatureContext> segmentOverrides = segmentContext.getOverrides();

if (segmentOverrides != null) {
for (FeatureContext featureContext : segmentOverrides) {
String featureKey = featureContext.getFeatureKey();
String featureName = featureContext.getName();

if (segmentFeatureContexts.containsKey(featureKey)) {
if (segmentFeatureContexts.containsKey(featureName)) {
ImmutablePair<String, FeatureContext> existing = segmentFeatureContexts
.get(featureKey);
.get(featureName);
FeatureContext existingFeatureContext = existing.getRight();

Double existingPriority = existingFeatureContext.getPriority() == null
Expand All @@ -79,7 +100,7 @@ private static SegmentEvaluationResult evaluateSegments(
continue;
}
}
segmentFeatureContexts.put(featureKey,
segmentFeatureContexts.put(featureName,
new ImmutablePair<String, FeatureContext>(
segmentContext.getName(), featureContext));
}
Expand All @@ -103,14 +124,13 @@ private static Flags evaluateFeatures(

if (contextFeatures != null) {
for (FeatureContext featureContext : contextFeatures.getAdditionalProperties().values()) {
if (segmentFeatureContexts.containsKey(featureContext.getFeatureKey())) {
if (segmentFeatureContexts.containsKey(featureContext.getName())) {
ImmutablePair<String, FeatureContext> segmentNameFeaturePair = segmentFeatureContexts
.get(featureContext.getFeatureKey());
.get(featureContext.getName());
featureContext = segmentNameFeaturePair.getRight();
flags.setAdditionalProperty(
featureContext.getName(),
new FlagResult().withEnabled(featureContext.getEnabled())
.withFeatureKey(featureContext.getFeatureKey())
.withName(featureContext.getName())
.withValue(featureContext.getValue())
.withReason(
Expand Down Expand Up @@ -148,10 +168,11 @@ private static FlagResult getFlagResultFromFeatureContext(
Float limit = startPercentage + weight.floatValue();
if (startPercentage <= percentageValue && percentageValue < limit) {
return new FlagResult().withEnabled(featureContext.getEnabled())
.withFeatureKey(featureContext.getFeatureKey())
.withName(featureContext.getName())
.withValue(variant.getValue())
.withReason("SPLIT; weight=" + weight.intValue())
.withReason("SPLIT; weight=" + BigDecimal.valueOf(weight)
.stripTrailingZeros()
.toPlainString())
.withMetadata(featureContext.getMetadata());
}
startPercentage = limit;
Expand All @@ -160,7 +181,6 @@ private static FlagResult getFlagResultFromFeatureContext(
}

return new FlagResult().withEnabled(featureContext.getEnabled())
.withFeatureKey(featureContext.getFeatureKey())
.withName(featureContext.getName())
.withValue(featureContext.getValue())
.withReason("DEFAULT")
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/com/flagsmith/mappers/EngineMappers.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ public static EvaluationContext mapContextAndIdentityDataToContext(

// Create identity context
IdentityContext identityContext = new IdentityContext()
.withIdentifier(identifier)
.withKey(context.getEnvironment().getKey() + "_" + identifier);
.withIdentifier(identifier);

// Map traits if provided
if (traits != null && !traits.isEmpty()) {
Expand Down Expand Up @@ -196,7 +195,6 @@ private static Map<String, SegmentContext> mapIdentityOverridesToSegments(
FeatureModel feature = featureState.getFeature();
FeatureContext featureContext = new FeatureContext()
.withKey("")
.withFeatureKey(String.valueOf(feature.getId()))
.withName(feature.getName())
.withEnabled(featureState.getEnabled())
.withValue(featureState.getValue())
Expand Down Expand Up @@ -349,7 +347,6 @@ private static double getMultivariateFeatureValuePriority(
private static FeatureContext mapFeatureStateToFeatureContext(FeatureStateModel featureState) {
FeatureContext featureContext = new FeatureContext()
.withKey(getFeatureStateKey(featureState))
.withFeatureKey(String.valueOf(featureState.getFeature().getId()))
.withName(featureState.getFeature().getName())
.withEnabled(featureState.getEnabled())
.withValue(featureState.getValue())
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/com/flagsmith/flagengine/enginetestdata
Submodule enginetestdata updated 158 files
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ public void testFromEvaluationResult__metadata__expected() throws FlagsmithClien
com.flagsmith.flagengine.Flags flagResults = new com.flagsmith.flagengine.Flags()
.withAdditionalProperty("feature_1", new FlagResult()
.withEnabled(true)
.withFeatureKey("feature_1")
.withName("Feature 1")
.withValue("value_1")
.withReason("DEFAULT")
.withMetadata(Map.of("flagsmithId", 1)))
.withAdditionalProperty("feature_2", new FlagResult()
.withEnabled(false)
.withFeatureKey("feature_2")
.withName("Feature 2")
.withValue(null)
.withReason("DEFAULT")
Expand Down