diff --git a/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java index 173749f..95c460d 100644 --- a/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java @@ -30,9 +30,6 @@ public class ExperimentEvaluator implements IExperimentEvaluator { private final ConditionEvaluator conditionEvaluator = new ConditionEvaluator(); - private final GrowthBookJsonUtils jsonUtils = GrowthBookJsonUtils.getInstance(); - private final ExperimentTracker experimentTracker = new ExperimentTracker(); - /** * Takes Context, Experiment and returns Experiment Result @@ -311,7 +308,8 @@ public ExperimentResult evaluateExperiment(Experiment ExperimentResult getExperimentResult( .build(); } - // Track experiments to trigger callbacks. - private boolean isExperimentTracked(Experiment experiment, ExperimentResult result) { - String experimentKey = experiment.getKey(); - - String key = ( - result.getHashAttribute() != null ? result.getHashAttribute() : "") - + (result.getHashValue() != null ? result.getHashValue() : "") - + (experimentKey + result.getVariationId()); - - // Add the experiment to the tracker if it doesn't exist. - if (!experimentTracker.isExperimentTracked(key)) { - experimentTracker.trackExperiment(key); - } - - return false; - } - private boolean isStickyBucketingEnabledForExperiment(EvaluationContext context, Experiment experiment) { return context.getOptions().getStickyBucketService() != null diff --git a/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java index 81323a3..972ef6f 100644 --- a/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java @@ -1,6 +1,8 @@ package growthbook.sdk.java.evaluators; import com.google.gson.JsonObject; +import growthbook.sdk.java.multiusermode.ExperimentTracker; +import growthbook.sdk.java.multiusermode.configurations.UserContext; import growthbook.sdk.java.util.GrowthBookJsonUtils; import growthbook.sdk.java.util.GrowthBookUtils; import growthbook.sdk.java.model.ParentCondition; @@ -280,13 +282,15 @@ public FeatureResult evaluateFeature( // If this was a remotely evaluated experiment, fire the tracking callbacks if (trackData != null && trackingCallBackWithUser != null) { - trackData.forEach(t -> - trackingCallBackWithUser.onTrack( - t.getExperiment(), - t.getResult().getExperimentResult(), - context.getUser() - ) - ); + trackData.forEach(t -> { + ExperimentResult trackedExpResult = t.getResult().getExperimentResult(); + Experiment trackedExperiment = t.getExperiment(); + ExperimentTracker experimentTracker = context.getGlobal().getExperimentTracker(); + UserContext userContext = context.getUser(); + + if (!GrowthBookUtils.isExperimentTracked(experimentTracker, trackedExperiment, trackedExpResult)) { + trackingCallBackWithUser.onTrack(trackedExperiment, trackedExpResult, userContext); + }}); } if (rule.getRange() == null) { diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java index 5385d4a..1cedf7e 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import growthbook.sdk.java.model.Experiment; import growthbook.sdk.java.model.Feature; +import growthbook.sdk.java.multiusermode.ExperimentTracker; import lombok.Builder; import lombok.Data; import lombok.Getter; @@ -48,4 +49,7 @@ public class GlobalContext { @Getter @Nullable private Map forcedFeatureValues; + + @Getter + private final ExperimentTracker experimentTracker = new ExperimentTracker(); } diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java index e9f62ca..dc6e71e 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java @@ -11,7 +11,6 @@ import growthbook.sdk.java.repository.FeatureRefreshStrategy; import growthbook.sdk.java.stickyBucketing.InMemoryStickyBucketServiceImpl; import growthbook.sdk.java.stickyBucketing.StickyBucketService; -import growthbook.sdk.java.util.ExperimentHelper; import lombok.Builder; import lombok.Data; import lombok.extern.slf4j.Slf4j; diff --git a/lib/src/main/java/growthbook/sdk/java/util/ExperimentHelper.java b/lib/src/main/java/growthbook/sdk/java/util/ExperimentHelper.java index 0e138bd..6b8aadf 100644 --- a/lib/src/main/java/growthbook/sdk/java/util/ExperimentHelper.java +++ b/lib/src/main/java/growthbook/sdk/java/util/ExperimentHelper.java @@ -3,19 +3,20 @@ import growthbook.sdk.java.model.Experiment; import growthbook.sdk.java.model.ExperimentResult; +import javax.annotation.Nullable; import java.util.HashSet; import java.util.Set; public class ExperimentHelper { private final Set trackedExperiments = new HashSet<>(); - public boolean isTracked(Experiment experiment, ExperimentResult result) { + public boolean isTracked(Experiment experiment, @Nullable ExperimentResult result) { String experimentKey = experiment.getKey(); + String hashAttribute = (result != null && result.getHashAttribute() != null) ? result.getHashAttribute() : ""; + String hashValue = (result != null && result.getHashValue() != null) ? result.getHashValue() : ""; + String variationId = (result != null) ? String.valueOf(result.getVariationId()) : ""; - String key = ( - result.getHashAttribute() != null ? result.getHashAttribute() : "") - + (result.getHashValue() != null ? result.getHashValue() : "") - + (experimentKey + result.getVariationId()); + String key = hashAttribute + hashValue + experimentKey + variationId; if (trackedExperiments.contains(key)) { return true; diff --git a/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java index 2a63c69..2452d04 100644 --- a/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java @@ -4,6 +4,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; import growthbook.sdk.java.model.GeneratedStickyBucketAssignmentDocModel; import growthbook.sdk.java.model.BucketRange; import growthbook.sdk.java.model.Feature; @@ -14,6 +16,7 @@ import growthbook.sdk.java.model.Namespace; import growthbook.sdk.java.model.StickyBucketVariation; import growthbook.sdk.java.model.VariationMeta; +import growthbook.sdk.java.multiusermode.ExperimentTracker; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; import growthbook.sdk.java.model.StickyAssignmentsDocument; import growthbook.sdk.java.multiusermode.util.TransformationUtil; @@ -889,4 +892,28 @@ public static Map mergeMaps(List> maps) { ); } + + // Track experiments to trigger callbacks. + public static boolean isExperimentTracked(ExperimentTracker experimentTracker, + Experiment experiment, + @Nullable ExperimentResult result) { + if (result == null) { + return false; + } + String experimentKey = experiment.getKey(); + + String key = ( + result.getHashAttribute() != null ? result.getHashAttribute() : "") + + (result.getHashValue() != null ? result.getHashValue() : "") + + (experimentKey + result.getVariationId()); + + boolean alreadyTracked = experimentTracker.isExperimentTracked(key); + + // Add the experiment to the tracker if it doesn't exist. + if (!alreadyTracked) { + experimentTracker.trackExperiment(key); + } + + return alreadyTracked; + } }