1616 */
1717package com .optimizely .ab .bucketing ;
1818
19+ import java .util .Collections ;
1920import java .util .List ;
2021
2122import javax .annotation .Nonnull ;
@@ -97,7 +98,8 @@ private Experiment bucketToExperiment(@Nonnull Group group,
9798
9899 @ Nonnull
99100 private DecisionResponse <Variation > bucketToVariation (@ Nonnull ExperimentCore experiment ,
100- @ Nonnull String bucketingId ) {
101+ @ Nonnull String bucketingId ,
102+ @ Nonnull DecisionPath decisionPath ) {
101103 DecisionReasons reasons = DefaultDecisionReasons .newInstance ();
102104
103105 // "salt" the bucket id using the experiment id
@@ -111,8 +113,25 @@ private DecisionResponse<Variation> bucketToVariation(@Nonnull ExperimentCore ex
111113 int bucketValue = generateBucketValue (hashCode );
112114 logger .debug ("Assigned bucket {} to user with bucketingId \" {}\" when bucketing to a variation." , bucketValue , bucketingId );
113115
116+ // Only apply CMAB traffic allocation logic if decision path is WITH_CMAB
117+ if (decisionPath == DecisionPath .WITH_CMAB && experiment instanceof Experiment && ((Experiment ) experiment ).getCmab () != null ) {
118+ // For CMAB experiments, the original trafficAllocation is kept empty for backward compatibility.
119+ // Use the traffic allocation defined in the CMAB block for bucketing instead.
120+ String message = reasons .addInfo ("Using CMAB traffic allocation for experiment \" %s\" " , experimentKey );
121+ logger .info (message );
122+ trafficAllocations = Collections .singletonList (
123+ new TrafficAllocation ("$" , ((Experiment ) experiment ).getCmab ().getTrafficAllocation ())
124+ );
125+ }
126+
114127 String bucketedVariationId = bucketToEntity (bucketValue , trafficAllocations );
115- if (bucketedVariationId != null ) {
128+ if (decisionPath == DecisionPath .WITH_CMAB && "$" .equals (bucketedVariationId )) {
129+ // for cmab experiments
130+ String message = reasons .addInfo ("User with bucketingId \" %s\" is bucketed into CMAB for experiment \" %s\" " , bucketingId , experimentKey );
131+ logger .info (message );
132+ return new DecisionResponse (new Variation ("$" , "$" ), reasons );
133+ }
134+ else if (bucketedVariationId != null ) {
116135 Variation bucketedVariation = experiment .getVariationIdToVariationMap ().get (bucketedVariationId );
117136 String variationKey = bucketedVariation .getKey ();
118137 String message = reasons .addInfo ("User with bucketingId \" %s\" is in variation \" %s\" of experiment \" %s\" ." , bucketingId , variationKey ,
@@ -134,12 +153,14 @@ private DecisionResponse<Variation> bucketToVariation(@Nonnull ExperimentCore ex
134153 * @param experiment The Experiment in which the user is to be bucketed.
135154 * @param bucketingId string A customer-assigned value used to create the key for the murmur hash.
136155 * @param projectConfig The current projectConfig
156+ * @param decisionPath enum for decision making logic
137157 * @return A {@link DecisionResponse} including the {@link Variation} that user is bucketed into (or null) and the decision reasons
138158 */
139159 @ Nonnull
140160 public DecisionResponse <Variation > bucket (@ Nonnull ExperimentCore experiment ,
141161 @ Nonnull String bucketingId ,
142- @ Nonnull ProjectConfig projectConfig ) {
162+ @ Nonnull ProjectConfig projectConfig ,
163+ @ Nonnull DecisionPath decisionPath ) {
143164 DecisionReasons reasons = DefaultDecisionReasons .newInstance ();
144165
145166 // ---------- Bucket User ----------
@@ -154,8 +175,6 @@ public DecisionResponse<Variation> bucket(@Nonnull ExperimentCore experiment,
154175 String message = reasons .addInfo ("User with bucketingId \" %s\" is not in any experiment of group %s." , bucketingId , experimentGroup .getId ());
155176 logger .info (message );
156177 return new DecisionResponse (null , reasons );
157- } else {
158-
159178 }
160179 // if the experiment a user is bucketed in within a group isn't the same as the experiment provided,
161180 // don't perform further bucketing within the experiment
@@ -172,11 +191,26 @@ public DecisionResponse<Variation> bucket(@Nonnull ExperimentCore experiment,
172191 }
173192 }
174193
175- DecisionResponse <Variation > decisionResponse = bucketToVariation (experiment , bucketingId );
194+ DecisionResponse <Variation > decisionResponse = bucketToVariation (experiment , bucketingId , decisionPath );
176195 reasons .merge (decisionResponse .getReasons ());
177196 return new DecisionResponse <>(decisionResponse .getResult (), reasons );
178197 }
179198
199+ /**
200+ * Assign a {@link Variation} of an {@link Experiment} to a user based on hashed value from murmurhash3.
201+ *
202+ * @param experiment The Experiment in which the user is to be bucketed.
203+ * @param bucketingId string A customer-assigned value used to create the key for the murmur hash.
204+ * @param projectConfig The current projectConfig
205+ * @return A {@link DecisionResponse} including the {@link Variation} that user is bucketed into (or null) and the decision reasons
206+ */
207+ @ Nonnull
208+ public DecisionResponse <Variation > bucket (@ Nonnull ExperimentCore experiment ,
209+ @ Nonnull String bucketingId ,
210+ @ Nonnull ProjectConfig projectConfig ) {
211+ return bucket (experiment , bucketingId , projectConfig , DecisionPath .WITHOUT_CMAB );
212+ }
213+
180214 //======== Helper methods ========//
181215
182216 /**
0 commit comments