Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e6f6dd2
Added Listener in getFeatureVariable
mnoman09 Mar 8, 2019
11e1d01
fixed findBugs Issue
mnoman09 Mar 8, 2019
708c6fe
changed OnDecision enum to Decision
mnoman09 Mar 12, 2019
c6bf1d8
Sending converted value to from string to object in listener decision…
mnoman09 Mar 12, 2019
4aa8c44
sending empty map in case when null is passed in attributes listener
mnoman09 Mar 13, 2019
017b0d2
did naming changes
mnoman09 Mar 14, 2019
3c20d8e
Merge branch 'master' into mnoman/getFeatVarListener
mfahadahmed Mar 18, 2019
ff5b878
Nit fixes and checking if listener is getting called
mnoman09 Mar 20, 2019
4fa7a37
Merge branch 'mnoman/getFeatVarListener' of github.com:optimizely/jav…
mnoman09 Mar 20, 2019
3dde5da
Updated getFeatureVariableValueForType to return casted object so tha…
mnoman09 Mar 21, 2019
158bee4
Refact: Added builder pattern in decision listener (#275)
mnoman09 Apr 1, 2019
9486ab1
Merge branch 'master' into mnoman/getFeatVarListener
mnoman09 Apr 1, 2019
52cd72a
Fixed Find bugs errors
mnoman09 Apr 2, 2019
21f24a2
Merge branch 'master' into mnoman/getFeatVarListener
aliabbasrizvi Apr 5, 2019
d728c85
fixed testcase
NomanShoaib Apr 5, 2019
c31522d
Merge branch 'master' into mnoman/getFeatVarListener
mnoman09 Apr 8, 2019
fc19aff
Merge branch 'master' into mnoman/getFeatVarListener
mnoman09 Apr 11, 2019
c34c3e7
Conflicts with master resolved
mnoman09 Apr 18, 2019
8a8b6eb
Nit fixes and remove extra check
mnoman09 Apr 18, 2019
21c8eb7
Feat: Updated getFeatVariable notification listener implementation a…
mnoman09 Apr 19, 2019
2b797fb
Updated naming convension of DecisionNotification keys
mnoman09 Apr 19, 2019
b070cc7
Merge branch 'master' into mnoman/getFeatVarListener
aliabbasrizvi Apr 22, 2019
2eee571
merged master and resolved conflicts
mnoman09 Apr 23, 2019
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
131 changes: 86 additions & 45 deletions core-api/src/main/java/com/optimizely/ab/Optimizely.java
Original file line number Diff line number Diff line change
Expand Up @@ -465,17 +465,13 @@ public Boolean getFeatureVariableBoolean(@Nonnull String featureKey,
return null;
}

String variableValue = getFeatureVariableValueForType(
featureKey,
variableKey,
userId,
attributes,
FeatureVariable.VariableType.BOOLEAN
);
if (variableValue != null) {
return Boolean.parseBoolean(variableValue);
}
return null;
return getFeatureVariableValueForType(
featureKey,
variableKey,
userId,
attributes,
FeatureVariable.VariableType.BOOLEAN
);
}

/**
Expand Down Expand Up @@ -514,20 +510,19 @@ public Double getFeatureVariableDouble(@Nonnull String featureKey,
return null;
}

String variableValue = getFeatureVariableValueForType(
featureKey,
variableKey,
userId,
attributes,
FeatureVariable.VariableType.DOUBLE
);
if (variableValue != null) {
try {
return Double.parseDouble(variableValue);
} catch (NumberFormatException exception) {
logger.error("NumberFormatException while trying to parse \"" + variableValue +
"\" as Double. " + exception);
}
Double variableValue = null;
try {
variableValue = getFeatureVariableValueForType(
featureKey,
variableKey,
userId,
attributes,
FeatureVariable.VariableType.DOUBLE
);
return variableValue;
} catch (Exception exception) {
logger.error("NumberFormatException while trying to parse \"" + variableValue +
"\" as Double. " + exception);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mnoman09 this and a other log statements in this PR append the exception as a string on log message. the logger should be passed the exception object as a last argument

}
return null;
}
Expand Down Expand Up @@ -567,21 +562,19 @@ public Integer getFeatureVariableInteger(@Nonnull String featureKey,
logger.error("Optimizely instance is not valid, failing getFeatureVariableInteger call.");
return null;
}

String variableValue = getFeatureVariableValueForType(
featureKey,
variableKey,
userId,
attributes,
FeatureVariable.VariableType.INTEGER
);
if (variableValue != null) {
try {
return Integer.parseInt(variableValue);
} catch (NumberFormatException exception) {
logger.error("NumberFormatException while trying to parse \"" + variableValue +
"\" as Integer. " + exception.toString());
try {
Integer variableValue = getFeatureVariableValueForType(
featureKey,
variableKey,
userId,
attributes,
FeatureVariable.VariableType.INTEGER
);
if (variableValue != null) {
return variableValue;
}
} catch (Exception exception) {
logger.error("NumberFormatException while trying to parse value as Integer. " + exception.toString());
}
return null;
}
Expand Down Expand Up @@ -631,11 +624,11 @@ public String getFeatureVariableString(@Nonnull String featureKey,
}

@VisibleForTesting
String getFeatureVariableValueForType(@Nonnull String featureKey,
@Nonnull String variableKey,
@Nonnull String userId,
@Nonnull Map<String, ?> attributes,
@Nonnull FeatureVariable.VariableType variableType) {
<T extends Object> T getFeatureVariableValueForType(@Nonnull String featureKey,
@Nonnull String variableKey,
@Nonnull String userId,
@Nonnull Map<String, ?> attributes,
@Nonnull FeatureVariable.VariableType variableType) {
if (featureKey == null) {
logger.warn("The featureKey parameter must be nonnull.");
return null;
Expand Down Expand Up @@ -668,6 +661,7 @@ String getFeatureVariableValueForType(@Nonnull String featureKey,
String variableValue = variable.getDefaultValue();
Map<String, ?> copiedAttributes = copyAttributes(attributes);
FeatureDecision featureDecision = decisionService.getVariationForFeature(featureFlag, userId, copiedAttributes);
Boolean featureEnabled = false;
if (featureDecision.variation != null) {
if (featureDecision.variation.getFeatureEnabled()) {
FeatureVariableUsageInstance featureVariableUsageInstance =
Expand All @@ -683,14 +677,61 @@ String getFeatureVariableValueForType(@Nonnull String featureKey,
featureKey, featureDecision.variation.getKey(), variableValue, variableKey
);
}
featureEnabled = featureDecision.variation.getFeatureEnabled();
} else {
logger.info("User \"{}\" was not bucketed into any variation for feature flag \"{}\". " +
"The default value \"{}\" for \"{}\" is being returned.",
userId, featureKey, variableValue, variableKey
);
}

return variableValue;
Object convertedValue = convertStringToType(variableValue, variableType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversion is now happening twice per api call. Once here and once in the originating method.


DecisionNotification decisionNotification = DecisionNotification.newFeatureVariableBuilder()
.withUserId(userId)
.withAttributes(copiedAttributes)
.withFeatureKey(featureKey)
.withFeatureEnabled(featureEnabled)
.withVariableKey(variableKey)
.withVariableType(variableType)
.withVariableValue(convertedValue)
.withFeatureDecision(featureDecision)
.build();


notificationCenter.sendNotifications(decisionNotification);

return (T) convertedValue;
}

// Helper method which takes type and variable value and convert it to object to use in Listener DecisionInfo object variable value
@VisibleForTesting
Object convertStringToType(String variableValue, FeatureVariable.VariableType type) {
if (variableValue != null) {
switch (type) {
case DOUBLE:
try {
return Double.parseDouble(variableValue);
} catch (NumberFormatException exception) {
logger.error("NumberFormatException while trying to parse \"" + variableValue +
"\" as Double. " + exception);
}
break;
case STRING:
return variableValue;
case BOOLEAN:
return Boolean.parseBoolean(variableValue);
case INTEGER:
try {
return Integer.parseInt(variableValue);
} catch (NumberFormatException exception) {
logger.error("NumberFormatException while trying to parse \"" + variableValue +
"\" as Integer. " + exception.toString());
}
break;
}
}
return null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package com.optimizely.ab.notification;


import com.optimizely.ab.bucketing.FeatureDecision;
import com.optimizely.ab.config.FeatureVariable;
import com.optimizely.ab.config.Variation;

import javax.annotation.Nonnull;
Expand Down Expand Up @@ -191,4 +193,98 @@ public DecisionNotification build() {
decisionInfo);
}
}
}

public static FeatureVariableDecisionNotificationBuilder newFeatureVariableBuilder() {
return new FeatureVariableDecisionNotificationBuilder();
}

public static class FeatureVariableDecisionNotificationBuilder {

public static final String FEATURE_KEY = "featureKey";
public static final String FEATURE_ENABLED = "featureEnabled";
public static final String SOURCE = "source";
public static final String SOURCE_INFO = "sourceInfo";
public static final String EXPERIMENT_KEY = "experimentKey";
public static final String VARIATION_KEY = "variationKey";
public static final String VARIABLE_KEY = "variableKey";
public static final String VARIABLE_TYPE = "variableType";
public static final String VARIABLE_VALUE = "variableValue";

private String featureKey;
private Boolean featureEnabled;
private FeatureDecision featureDecision;
private String variableKey;
private FeatureVariable.VariableType variableType;
private Object variableValue;
private String userId;
private Map<String, ?> attributes;
private Map<String, Object> decisionInfo;

protected FeatureVariableDecisionNotificationBuilder() {
}

public FeatureVariableDecisionNotificationBuilder withUserId(String userId) {
this.userId = userId;
return this;
}

public FeatureVariableDecisionNotificationBuilder withAttributes(Map<String, ?> attributes) {
this.attributes = attributes;
return this;
}

public FeatureVariableDecisionNotificationBuilder withFeatureKey(String featureKey) {
this.featureKey = featureKey;
return this;
}

public FeatureVariableDecisionNotificationBuilder withFeatureEnabled(boolean featureEnabled) {
this.featureEnabled = featureEnabled;
return this;
}

public FeatureVariableDecisionNotificationBuilder withFeatureDecision(FeatureDecision featureDecision) {
this.featureDecision = featureDecision;
return this;
}

public FeatureVariableDecisionNotificationBuilder withVariableKey(String variableKey) {
this.variableKey = variableKey;
return this;
}

public FeatureVariableDecisionNotificationBuilder withVariableType(FeatureVariable.VariableType variableType) {
this.variableType = variableType;
return this;
}

public FeatureVariableDecisionNotificationBuilder withVariableValue(Object variableValue) {
this.variableValue = variableValue;
return this;
}

public DecisionNotification build() {
decisionInfo = new HashMap<>();
decisionInfo.put(FEATURE_KEY, featureKey);
decisionInfo.put(FEATURE_ENABLED, featureEnabled);
decisionInfo.put(VARIABLE_KEY, variableKey);
decisionInfo.put(VARIABLE_TYPE, variableType);
decisionInfo.put(VARIABLE_VALUE, variableValue);
Map<String, String> sourceInfo = new HashMap<>();
if (featureDecision != null && FeatureDecision.DecisionSource.FEATURE_TEST.equals(featureDecision.decisionSource)) {
sourceInfo.put(EXPERIMENT_KEY, featureDecision.experiment.getKey());
sourceInfo.put(VARIATION_KEY, featureDecision.variation.getKey());
decisionInfo.put(SOURCE, featureDecision.decisionSource);
} else {
decisionInfo.put(SOURCE, FeatureDecision.DecisionSource.ROLLOUT);
}
decisionInfo.put(SOURCE_INFO, sourceInfo);

return new DecisionNotification(
NotificationCenter.DecisionNotificationType.FEATURE_VARIABLE.toString(),
userId,
attributes,
decisionInfo);
}
}
}
Loading