Skip to content

Commit 78f45bf

Browse files
update: enhance DecisionService, FeatureDecision, and DecisionResponse to support CMAB UUID handling
1 parent 9905026 commit 78f45bf

File tree

3 files changed

+42
-8
lines changed

3 files changed

+42
-8
lines changed

core-api/src/main/java/com/optimizely/ab/bucketing/DecisionService.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
* 3. Checking sticky bucketing
6161
* 4. Checking audience targeting
6262
* 5. Using Murmurhash3 to bucket the user.
63+
* 6. Handling CMAB (Contextual Multi-Armed Bandit) experiments for dynamic variation selection
6364
*/
6465
public class DecisionService {
6566

@@ -153,18 +154,19 @@ public DecisionResponse<Variation> getVariation(@Nonnull Experiment experiment,
153154
reasons.merge(decisionMeetAudience.getReasons());
154155
if (decisionMeetAudience.getResult()) {
155156
String bucketingId = getBucketingId(user.getUserId(), user.getAttributes());
156-
157+
String cmabUUID = null;
157158
if (isCmabExperiment(experiment)) {
158159
DecisionResponse<CmabDecision> cmabDecision = getDecisionForCmabExperiment(projectConfig, experiment, user, bucketingId, options);
159160
reasons.merge(cmabDecision.getReasons());
160161

161162
if (cmabDecision.isError()) {
162-
return new DecisionResponse<>(null, reasons, true);
163+
return new DecisionResponse<>(null, reasons, true, null);
163164
}
164165

165166
CmabDecision cmabResult = cmabDecision.getResult();
166167
if (cmabResult != null) {
167168
String variationId = cmabResult.getVariationId();
169+
cmabUUID = cmabResult.getCmabUUID();
168170
variation = experiment.getVariationIdToVariationMap().get(variationId);
169171
}
170172
} else {
@@ -182,7 +184,7 @@ public DecisionResponse<Variation> getVariation(@Nonnull Experiment experiment,
182184
}
183185
}
184186

185-
return new DecisionResponse(variation, reasons);
187+
return new DecisionResponse<>(variation, reasons, false, cmabUUID);
186188
}
187189

188190
String message = reasons.addInfo("User \"%s\" does not meet conditions to be in experiment \"%s\".", user.getUserId(), experiment.getKey());

core-api/src/main/java/com/optimizely/ab/bucketing/FeatureDecision.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ public class FeatureDecision {
3939
@Nullable
4040
public DecisionSource decisionSource;
4141

42+
/**
43+
* The CMAB UUID for Contextual Multi-Armed Bandit experiments.
44+
*/
45+
@Nullable
46+
public String cmabUUID;
47+
4248
public enum DecisionSource {
4349
FEATURE_TEST("feature-test"),
4450
ROLLOUT("rollout"),
@@ -68,6 +74,23 @@ public FeatureDecision(@Nullable ExperimentCore experiment, @Nullable Variation
6874
this.experiment = experiment;
6975
this.variation = variation;
7076
this.decisionSource = decisionSource;
77+
this.cmabUUID = null;
78+
}
79+
80+
/**
81+
* Initialize a FeatureDecision object with CMAB UUID.
82+
*
83+
* @param experiment The {@link ExperimentCore} the Feature is associated with.
84+
* @param variation The {@link Variation} the user was bucketed into.
85+
* @param decisionSource The source of the variation.
86+
* @param cmabUUID The CMAB UUID for Contextual Multi-Armed Bandit experiments.
87+
*/
88+
public FeatureDecision(@Nullable ExperimentCore experiment, @Nullable Variation variation,
89+
@Nullable DecisionSource decisionSource, @Nullable String cmabUUID) {
90+
this.experiment = experiment;
91+
this.variation = variation;
92+
this.decisionSource = decisionSource;
93+
this.cmabUUID = cmabUUID;
7194
}
7295

7396
@Override
@@ -79,13 +102,15 @@ public boolean equals(Object o) {
79102

80103
if (variation != null ? !variation.equals(that.variation) : that.variation != null)
81104
return false;
82-
return decisionSource == that.decisionSource;
105+
if (decisionSource != that.decisionSource) return false;
106+
return cmabUUID != null ? cmabUUID.equals(that.cmabUUID) : that.cmabUUID == null;
83107
}
84108

85109
@Override
86110
public int hashCode() {
87111
int result = variation != null ? variation.hashCode() : 0;
88112
result = 31 * result + (decisionSource != null ? decisionSource.hashCode() : 0);
113+
result = 31 * result + (cmabUUID != null ? cmabUUID.hashCode() : 0);
89114
return result;
90115
}
91116
}

core-api/src/main/java/com/optimizely/ab/optimizelydecision/DecisionResponse.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,25 @@ public class DecisionResponse<T> {
2323
private T result;
2424
private DecisionReasons reasons;
2525
private boolean error;
26+
private String cmabUUID;
2627

27-
public DecisionResponse(@Nullable T result, @Nonnull DecisionReasons reasons, @Nonnull boolean error) {
28+
public DecisionResponse(@Nullable T result, @Nonnull DecisionReasons reasons, @Nonnull boolean error, @Nullable String cmabUUID) {
2829
this.result = result;
2930
this.reasons = reasons;
3031
this.error = error;
32+
this.cmabUUID = cmabUUID;
3133
}
3234

3335
public DecisionResponse(@Nullable T result, @Nonnull DecisionReasons reasons) {
34-
this(result, reasons, false);
36+
this(result, reasons, false, null);
3537
}
3638

3739
public static <E> DecisionResponse<E> responseNoReasons(@Nullable E result) {
38-
return new DecisionResponse<>(result, DefaultDecisionReasons.newInstance(), false);
40+
return new DecisionResponse<>(result, DefaultDecisionReasons.newInstance(), false, null);
3941
}
4042

4143
public static <E> DecisionResponse<E> nullNoReasons() {
42-
return new DecisionResponse<>(null, DefaultDecisionReasons.newInstance(), false);
44+
return new DecisionResponse<>(null, DefaultDecisionReasons.newInstance(), false, null);
4345
}
4446

4547
@Nullable
@@ -56,4 +58,9 @@ public DecisionReasons getReasons() {
5658
public boolean isError(){
5759
return error;
5860
}
61+
62+
@Nullable
63+
public String getCmabUUID() {
64+
return cmabUUID;
65+
}
5966
}

0 commit comments

Comments
 (0)