Skip to content

Commit f803cd7

Browse files
committed
add option and reasons to condition evaluation
1 parent a93fc23 commit f803cd7

File tree

12 files changed

+204
-110
lines changed

12 files changed

+204
-110
lines changed

core-api/src/main/java/com/optimizely/ab/config/audience/AndCondition.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
package com.optimizely.ab.config.audience;
1818

1919
import com.optimizely.ab.config.ProjectConfig;
20+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
21+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
2022

2123
import javax.annotation.Nonnull;
2224
import javax.annotation.Nullable;
23-
import javax.annotation.concurrent.Immutable;
25+
import java.util.Collections;
2426
import java.util.List;
2527
import java.util.Map;
2628

@@ -40,7 +42,10 @@ public List<Condition> getConditions() {
4042
}
4143

4244
@Nullable
43-
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
45+
public Boolean evaluate(ProjectConfig config,
46+
Map<String, ?> attributes,
47+
List<OptimizelyDecideOption> options,
48+
DecisionReasons reasons) {
4449
if (conditions == null) return null;
4550
boolean foundNull = false;
4651
// According to the matrix where:
@@ -51,7 +56,7 @@ public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
5156
// true and true is true
5257
// null and null is null
5358
for (Condition condition : conditions) {
54-
Boolean conditionEval = condition.evaluate(config, attributes);
59+
Boolean conditionEval = condition.evaluate(config, attributes, options, reasons);
5560
if (conditionEval == null) {
5661
foundNull = true;
5762
} else if (!conditionEval) { // false with nulls or trues is false.
@@ -67,6 +72,11 @@ public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
6772
return true; // otherwise, return true
6873
}
6974

75+
@Nullable
76+
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
77+
return evaluate(config, attributes, Collections.emptyList(), new DecisionReasons());
78+
}
79+
7080
@Override
7181
public String toString() {
7282
StringBuilder s = new StringBuilder();

core-api/src/main/java/com/optimizely/ab/config/audience/AudienceIdCondition.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818

1919
import com.fasterxml.jackson.annotation.JsonCreator;
2020
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21-
import com.fasterxml.jackson.annotation.JsonProperty;
2221
import com.optimizely.ab.config.ProjectConfig;
23-
import com.optimizely.ab.internal.InvalidAudienceCondition;
22+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
23+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
2424
import org.slf4j.Logger;
2525
import org.slf4j.LoggerFactory;
2626

2727
import javax.annotation.Nullable;
28-
import javax.annotation.concurrent.Immutable;
28+
import java.util.Collections;
29+
import java.util.List;
2930
import java.util.Map;
3031
import java.util.Objects;
3132

@@ -66,20 +67,29 @@ public String getAudienceId() {
6667

6768
@Nullable
6869
@Override
69-
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
70+
public Boolean evaluate(ProjectConfig config,
71+
Map<String, ?> attributes,
72+
List<OptimizelyDecideOption> options,
73+
DecisionReasons reasons) {
7074
if (config != null) {
7175
audience = config.getAudienceIdMapping().get(audienceId);
7276
}
7377
if (audience == null) {
74-
logger.error("Audience {} could not be found.", audienceId);
78+
String message = reasons.addInfoF("Audience %s could not be found.", audienceId);
79+
logger.error(message);
7580
return null;
7681
}
7782
logger.debug("Starting to evaluate audience \"{}\" with conditions: {}.", audience.getId(), audience.getConditions());
78-
Boolean result = audience.getConditions().evaluate(config, attributes);
83+
Boolean result = audience.getConditions().evaluate(config, attributes, options, reasons);
7984
logger.debug("Audience \"{}\" evaluated to {}.", audience.getId(), result);
8085
return result;
8186
}
8287

88+
@Nullable
89+
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
90+
return evaluate(config, attributes, Collections.emptyList(), new DecisionReasons());
91+
}
92+
8393
@Override
8494
public boolean equals(Object o) {
8595
if (this == o) return true;

core-api/src/main/java/com/optimizely/ab/config/audience/Condition.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,25 @@
1717
package com.optimizely.ab.config.audience;
1818

1919
import com.optimizely.ab.config.ProjectConfig;
20+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
21+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
2022

2123
import javax.annotation.Nullable;
24+
import java.util.List;
2225
import java.util.Map;
2326

2427
/**
2528
* Interface implemented by all conditions condition objects to aid in condition evaluation.
2629
*/
2730
public interface Condition<T> {
2831

32+
@Nullable
33+
Boolean evaluate(ProjectConfig config,
34+
Map<String, ?> attributes,
35+
List<OptimizelyDecideOption> options,
36+
DecisionReasons reasons);
37+
2938
@Nullable
3039
Boolean evaluate(ProjectConfig config, Map<String, ?> attributes);
40+
3141
}

core-api/src/main/java/com/optimizely/ab/config/audience/EmptyCondition.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,27 @@
1616
package com.optimizely.ab.config.audience;
1717

1818
import com.optimizely.ab.config.ProjectConfig;
19+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
20+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
1921

2022
import javax.annotation.Nullable;
23+
import java.util.Collections;
24+
import java.util.List;
2125
import java.util.Map;
2226

2327
public class EmptyCondition<T> implements Condition<T> {
2428
@Nullable
2529
@Override
26-
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
30+
public Boolean evaluate(ProjectConfig config,
31+
Map<String, ?> attributes,
32+
List<OptimizelyDecideOption> options,
33+
DecisionReasons reasons) {
2734
return true;
2835
}
2936

37+
@Nullable
38+
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
39+
return evaluate(config, attributes, Collections.emptyList(), new DecisionReasons());
40+
}
41+
3042
}

core-api/src/main/java/com/optimizely/ab/config/audience/NotCondition.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
package com.optimizely.ab.config.audience;
1818

1919
import com.optimizely.ab.config.ProjectConfig;
20+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
21+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
2022

2123
import javax.annotation.Nullable;
2224
import javax.annotation.concurrent.Immutable;
2325
import javax.annotation.Nonnull;
2426

27+
import java.util.Collections;
28+
import java.util.List;
2529
import java.util.Map;
2630

2731
/**
@@ -41,12 +45,20 @@ public Condition getCondition() {
4145
}
4246

4347
@Nullable
44-
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
48+
public Boolean evaluate(ProjectConfig config,
49+
Map<String, ?> attributes,
50+
List<OptimizelyDecideOption> options,
51+
DecisionReasons reasons) {
4552

46-
Boolean conditionEval = condition == null ? null : condition.evaluate(config, attributes);
53+
Boolean conditionEval = condition == null ? null : condition.evaluate(config, attributes, options, reasons);
4754
return (conditionEval == null ? null : !conditionEval);
4855
}
4956

57+
@Nullable
58+
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
59+
return evaluate(config, attributes, Collections.emptyList(), new DecisionReasons());
60+
}
61+
5062
@Override
5163
public String toString() {
5264
StringBuilder s = new StringBuilder();

core-api/src/main/java/com/optimizely/ab/config/audience/NullCondition.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,26 @@
1616
package com.optimizely.ab.config.audience;
1717

1818
import com.optimizely.ab.config.ProjectConfig;
19+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
20+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
1921

2022
import javax.annotation.Nullable;
23+
import java.util.Collections;
24+
import java.util.List;
2125
import java.util.Map;
2226

2327
public class NullCondition<T> implements Condition<T> {
2428
@Nullable
2529
@Override
26-
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
30+
public Boolean evaluate(ProjectConfig config,
31+
Map<String, ?> attributes,
32+
List<OptimizelyDecideOption> options,
33+
DecisionReasons reasons) {
2734
return null;
2835
}
36+
37+
@Nullable
38+
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
39+
return evaluate(config, attributes, Collections.emptyList(), new DecisionReasons());
40+
}
2941
}

core-api/src/main/java/com/optimizely/ab/config/audience/OrCondition.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
package com.optimizely.ab.config.audience;
1818

1919
import com.optimizely.ab.config.ProjectConfig;
20+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
21+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
2022

2123
import javax.annotation.Nonnull;
2224
import javax.annotation.Nullable;
2325
import javax.annotation.concurrent.Immutable;
26+
import java.util.Collections;
2427
import java.util.List;
2528
import java.util.Map;
2629

@@ -45,11 +48,14 @@ public List<Condition> getConditions() {
4548
// false or false is false
4649
// null or null is null
4750
@Nullable
48-
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
51+
public Boolean evaluate(ProjectConfig config,
52+
Map<String, ?> attributes,
53+
List<OptimizelyDecideOption> options,
54+
DecisionReasons reasons) {
4955
if (conditions == null) return null;
5056
boolean foundNull = false;
5157
for (Condition condition : conditions) {
52-
Boolean conditionEval = condition.evaluate(config, attributes);
58+
Boolean conditionEval = condition.evaluate(config, attributes, options, reasons);
5359
if (conditionEval == null) { // true with falses and nulls is still true
5460
foundNull = true;
5561
} else if (conditionEval) {
@@ -65,6 +71,11 @@ public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
6571
return false;
6672
}
6773

74+
@Nullable
75+
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
76+
return evaluate(config, attributes, Collections.emptyList(), new DecisionReasons());
77+
}
78+
6879
@Override
6980
public String toString() {
7081
StringBuilder s = new StringBuilder();

core-api/src/main/java/com/optimizely/ab/config/audience/UserAttribute.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121
import com.fasterxml.jackson.annotation.JsonProperty;
2222
import com.optimizely.ab.config.ProjectConfig;
2323
import com.optimizely.ab.config.audience.match.*;
24+
import com.optimizely.ab.optimizelydecision.DecisionReasons;
25+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
2426
import org.slf4j.Logger;
2527
import org.slf4j.LoggerFactory;
2628

2729
import javax.annotation.Nonnull;
2830
import javax.annotation.Nullable;
2931
import javax.annotation.concurrent.Immutable;
3032
import java.util.Collections;
33+
import java.util.List;
3134
import java.util.Map;
3235

3336
/**
@@ -71,7 +74,10 @@ public Object getValue() {
7174
}
7275

7376
@Nullable
74-
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
77+
public Boolean evaluate(ProjectConfig config,
78+
Map<String, ?> attributes,
79+
List<OptimizelyDecideOption> options,
80+
DecisionReasons reasons) {
7581
if (attributes == null) {
7682
attributes = Collections.emptyMap();
7783
}
@@ -118,6 +124,11 @@ public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
118124
return null;
119125
}
120126

127+
@Nullable
128+
public Boolean evaluate(ProjectConfig config, Map<String, ?> attributes) {
129+
return evaluate(config, attributes, Collections.emptyList(), new DecisionReasons());
130+
}
131+
121132
@Override
122133
public String toString() {
123134
final String valueStr;

core-api/src/main/java/com/optimizely/ab/internal/ExperimentUtils.java

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ public static boolean doesUserMeetAudienceConditions(@Nonnull ProjectConfig proj
8686
@Nonnull DecisionReasons reasons) {
8787
if (experiment.getAudienceConditions() != null) {
8888
logger.debug("Evaluating audiences for {} \"{}\": {}.", loggingEntityType, loggingKey, experiment.getAudienceConditions());
89-
Boolean resolveReturn = evaluateAudienceConditions(projectConfig, experiment, attributes, loggingEntityType, loggingKey);
89+
Boolean resolveReturn = evaluateAudienceConditions(projectConfig, experiment, attributes, loggingEntityType, loggingKey, options, reasons);
9090
return resolveReturn == null ? false : resolveReturn;
9191
} else {
92-
Boolean resolveReturn = evaluateAudience(projectConfig, experiment, attributes, loggingEntityType, loggingKey);
92+
Boolean resolveReturn = evaluateAudience(projectConfig, experiment, attributes, loggingEntityType, loggingKey, options, reasons);
9393
return Boolean.TRUE.equals(resolveReturn);
9494
}
9595
}
@@ -137,23 +137,14 @@ public static Boolean evaluateAudience(@Nonnull ProjectConfig projectConfig,
137137

138138
logger.debug("Evaluating audiences for {} \"{}\": {}.", loggingEntityType, loggingKey, conditions);
139139

140-
Boolean result = implicitOr.evaluate(projectConfig, attributes);
140+
Boolean result = implicitOr.evaluate(projectConfig, attributes, options, reasons);
141141

142142
String message = reasons.addInfoF("Audiences for %s \"%s\" collectively evaluated to %s.", loggingEntityType, loggingKey, result);
143143
logger.info(message);
144144

145145
return result;
146146
}
147147

148-
@Nullable
149-
public static Boolean evaluateAudience(@Nonnull ProjectConfig projectConfig,
150-
@Nonnull Experiment experiment,
151-
@Nonnull Map<String, ?> attributes,
152-
@Nonnull String loggingEntityType,
153-
@Nonnull String loggingKey) {
154-
return evaluateAudience(projectConfig, experiment, attributes, loggingEntityType, loggingKey, Collections.emptyList(), new DecisionReasons());
155-
}
156-
157148
@Nullable
158149
public static Boolean evaluateAudienceConditions(@Nonnull ProjectConfig projectConfig,
159150
@Nonnull Experiment experiment,
@@ -167,7 +158,7 @@ public static Boolean evaluateAudienceConditions(@Nonnull ProjectConfig projectC
167158
if (conditions == null) return null;
168159

169160
try {
170-
Boolean result = conditions.evaluate(projectConfig, attributes);
161+
Boolean result = conditions.evaluate(projectConfig, attributes, options, reasons);
171162
String message = reasons.addInfoF("Audiences for %s \"%s\" collectively evaluated to %s.", loggingEntityType, loggingKey, result);
172163
logger.info(message);
173164
return result;
@@ -178,13 +169,4 @@ public static Boolean evaluateAudienceConditions(@Nonnull ProjectConfig projectC
178169
}
179170
}
180171

181-
@Nullable
182-
public static Boolean evaluateAudienceConditions(@Nonnull ProjectConfig projectConfig,
183-
@Nonnull Experiment experiment,
184-
@Nonnull Map<String, ?> attributes,
185-
@Nonnull String loggingEntityType,
186-
@Nonnull String loggingKey) {
187-
return evaluateAudienceConditions(projectConfig, experiment, attributes, loggingEntityType, loggingKey, Collections.emptyList(), new DecisionReasons());
188-
}
189-
190172
}

0 commit comments

Comments
 (0)