Skip to content

Commit f0ca996

Browse files
authored
Update DecisionService to return a source for feature variation (#153)
1 parent 5f2f3f5 commit f0ca996

File tree

6 files changed

+317
-235
lines changed

6 files changed

+317
-235
lines changed

core-api/src/main/java/com/optimizely/ab/Optimizely.java

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.optimizely.ab.annotations.VisibleForTesting;
1919
import com.optimizely.ab.bucketing.Bucketer;
2020
import com.optimizely.ab.bucketing.DecisionService;
21+
import com.optimizely.ab.bucketing.FeatureDecision;
2122
import com.optimizely.ab.bucketing.UserProfileService;
2223
import com.optimizely.ab.config.Attribute;
2324
import com.optimizely.ab.config.EventType;
@@ -41,19 +42,21 @@
4142
import com.optimizely.ab.internal.EventTagUtils;
4243
import com.optimizely.ab.notification.NotificationBroadcaster;
4344
import com.optimizely.ab.notification.NotificationListener;
45+
4446
import org.slf4j.Logger;
4547
import org.slf4j.LoggerFactory;
4648

47-
import javax.annotation.CheckForNull;
48-
import javax.annotation.Nonnull;
49-
import javax.annotation.Nullable;
50-
import javax.annotation.concurrent.ThreadSafe;
5149
import java.util.ArrayList;
5250
import java.util.Collections;
5351
import java.util.HashMap;
5452
import java.util.List;
5553
import java.util.Map;
5654

55+
import javax.annotation.CheckForNull;
56+
import javax.annotation.Nonnull;
57+
import javax.annotation.Nullable;
58+
import javax.annotation.concurrent.ThreadSafe;
59+
5760
/**
5861
* Top-level container class for Optimizely functionality.
5962
* Thread-safe, so can be created as a singleton and safely passed around.
@@ -324,34 +327,29 @@ public void track(@Nonnull String eventName,
324327
@Nonnull Map<String, String> attributes) {
325328
FeatureFlag featureFlag = projectConfig.getFeatureKeyMapping().get(featureKey);
326329
if (featureFlag == null) {
327-
logger.info("No feature flag was found for key \"" + featureKey + "\".");
330+
logger.info("No feature flag was found for key \"{}\".", featureKey);
328331
return false;
329332
}
330333

331334
Map<String, String> filteredAttributes = filterAttributes(projectConfig, attributes);
332335

333-
Variation variation = decisionService.getVariationForFeature(featureFlag, userId, filteredAttributes);
334-
335-
if (variation != null) {
336-
Experiment experiment = projectConfig.getExperimentForVariationId(variation.getId());
337-
if (experiment != null) {
338-
// the user is in an experiment for the feature
336+
FeatureDecision featureDecision = decisionService.getVariationForFeature(featureFlag, userId, filteredAttributes);
337+
if (featureDecision.variation != null) {
338+
if (featureDecision.decisionSource.equals(FeatureDecision.DecisionSource.EXPERIMENT)) {
339339
sendImpression(
340340
projectConfig,
341-
experiment,
341+
featureDecision.experiment,
342342
userId,
343343
filteredAttributes,
344-
variation);
345-
}
346-
else {
347-
logger.info("The user \"" + userId +
348-
"\" is not being experimented on in feature \"" + featureKey + "\".");
344+
featureDecision.variation);
345+
} else {
346+
logger.info("The user \"{}\" is not included in an experiment for feature \"{}\".",
347+
userId, featureKey);
349348
}
350-
logger.info("Feature \"" + featureKey + "\" is enabled for user \"" + userId + "\".");
349+
logger.info("Feature \"{}\" is enabled for user \"{}\".", featureKey, userId);
351350
return true;
352-
}
353-
else {
354-
logger.info("Feature \"" + featureKey + "\" is not enabled for user \"" + userId + "\".");
351+
} else {
352+
logger.info("Feature \"{}\" is not enabled for user \"{}\".", featureKey, userId);
355353
return false;
356354
}
357355
}
@@ -433,10 +431,9 @@ public void track(@Nonnull String eventName,
433431
if (variableValue != null) {
434432
try {
435433
return Double.parseDouble(variableValue);
436-
}
437-
catch (NumberFormatException exception) {
434+
} catch (NumberFormatException exception) {
438435
logger.error("NumberFormatException while trying to parse \"" + variableValue +
439-
"\" as Double. " + exception);
436+
"\" as Double. " + exception);
440437
}
441438
}
442439
return null;
@@ -479,10 +476,9 @@ public void track(@Nonnull String eventName,
479476
if (variableValue != null) {
480477
try {
481478
return Integer.parseInt(variableValue);
482-
}
483-
catch (NumberFormatException exception) {
479+
} catch (NumberFormatException exception) {
484480
logger.error("NumberFormatException while trying to parse \"" + variableValue +
485-
"\" as Integer. " + exception.toString());
481+
"\" as Integer. " + exception.toString());
486482
}
487483
}
488484
return null;
@@ -531,17 +527,16 @@ String getFeatureVariableValueForType(@Nonnull String featureKey,
531527
@Nonnull LiveVariable.VariableType variableType) {
532528
FeatureFlag featureFlag = projectConfig.getFeatureKeyMapping().get(featureKey);
533529
if (featureFlag == null) {
534-
logger.info("No feature flag was found for key \"" + featureKey + "\".");
530+
logger.info("No feature flag was found for key \"{}\".", featureKey);
535531
return null;
536532
}
537533

538534
LiveVariable variable = featureFlag.getVariableKeyToLiveVariableMap().get(variableKey);
539-
if (variable == null) {
540-
logger.info("No feature variable was found for key \"" + variableKey + "\" in feature flag \"" +
541-
featureKey + "\".");
535+
if (variable == null) {
536+
logger.info("No feature variable was found for key \"{}\" in feature flag \"{}\".",
537+
variableKey, featureKey);
542538
return null;
543-
}
544-
else if (!variable.getType().equals(variableType)) {
539+
} else if (!variable.getType().equals(variableType)) {
545540
logger.info("The feature variable \"" + variableKey +
546541
"\" is actually of type \"" + variable.getType().toString() +
547542
"\" type. You tried to access it as type \"" + variableType.toString() +
@@ -551,23 +546,19 @@ else if (!variable.getType().equals(variableType)) {
551546

552547
String variableValue = variable.getDefaultValue();
553548

554-
Variation variation = decisionService.getVariationForFeature(featureFlag, userId, attributes);
555-
556-
if (variation != null) {
549+
FeatureDecision featureDecision = decisionService.getVariationForFeature(featureFlag, userId, attributes);
550+
if (featureDecision.variation != null) {
557551
LiveVariableUsageInstance liveVariableUsageInstance =
558-
variation.getVariableIdToLiveVariableUsageInstanceMap().get(variable.getId());
552+
featureDecision.variation.getVariableIdToLiveVariableUsageInstanceMap().get(variable.getId());
559553
if (liveVariableUsageInstance != null) {
560554
variableValue = liveVariableUsageInstance.getValue();
561-
}
562-
else {
555+
} else {
563556
variableValue = variable.getDefaultValue();
564557
}
565-
}
566-
else {
567-
logger.info("User \"" + userId +
568-
"\" was not bucketed into any variation for feature flag \"" + featureKey +
569-
"\". The default value \"" + variableValue +
570-
"\" for \"" + variableKey + "\" is being returned."
558+
} else {
559+
logger.info("User \"{}\" was not bucketed into any variation for feature flag \"{}\". " +
560+
"The default value \"{}\" for \"{}\" is being returned.",
561+
userId, featureKey, variableValue, variableKey
571562
);
572563
}
573564

0 commit comments

Comments
 (0)