Skip to content

Commit efbda89

Browse files
[FSSDK-11170] update: decision service methods for cmab (#583)
* update: add CmabService to Optimizely class and builder * update: integrate CMAB service into OptimizelyFactory * update: change CmabService field to non-nullable in Optimizely class * update: add CmabService to DecisionService and its tests * update: implement CMAB traffic allocation in Bucketer and DecisionService * update: enhance DecisionService, FeatureDecision, and DecisionResponse to support CMAB UUID handling * update: enhance DecisionService and DecisionMessage to handle errors and include CMAB UUIDs in responses * update: add validConfigJsonCMAB method to DatafileProjectConfigTestUtils for CMAB configuration * update: add tests to verify precedence of whitelisted and forced variations over CMAB service decisions in DecisionService * update: add test to verify error handling in getVariation for CMAB service failures * update: modify DecisionResponse to include additional error handling information * update: fix error handling assertion in DecisionServiceTest to correctly verify error state * update: add tests for CMAB experiment variations in DecisionService * update: implement decision-making methods to skip CMAB logic in Optimizely and DecisionService * update: add methods to OptimizelyUserContext for decision-making without CMAB logic * update: add asynchronous decision-making methods in OptimizelyUserContext and related fetcher classes * update: add decision-making methods without CMAB logic in OptimizelyUserContextTest * update: remove unused parameter 'useCmab' from DecisionService method documentation * update: rename methods to use 'Sync' suffix for clarity in decision-making logic * update: return cmab error decision whenever found * update: enhance error handling by specifying CMAB error messages in decision responses * update: improve error handling by checking for null values in experiment key retrieval * update: fix CMAB error handling by providing a valid Experiment in FeatureDecision * update: add Javadoc comments for async decision methods and config creation in CMAB client * update: refactor build to use cmabClient instead of default service * update: refactor DefaultCmabClient to utilize CmabClientHelper * update: refactor AsyncDecisionsFetcher to AsyncDecisionFetcher and enhance decision handling * update: add missing copyright notice and license information to CmabClientHelper * update: enhance CMAB handling in bucketing and decision services, add backward compatibility for mobile apps * update: add backward compatibility support for Android sync and async decisions in OptimizelyUserContext * update: add empty list parameter to decision methods in OptimizelyUserContextTest for consistency * update: replace null with empty list parameter in async decision method for consistency * update: add useCmab parameter to decideForKeys methods for enhanced decision handling * Update core-api/src/main/java/com/optimizely/ab/Optimizely.java Co-authored-by: Jae Kim <[email protected]> * update: refactor decision-making logic to use DecisionPath enum for clarity and maintainability * Update core-api/src/main/java/com/optimizely/ab/Optimizely.java Co-authored-by: Jae Kim <[email protected]> * Update core-api/src/main/java/com/optimizely/ab/Optimizely.java Co-authored-by: Jae Kim <[email protected]> * update: modify OptimizelyUserContext to change optimizely field to package-private and add copyright notice to DecisionPath * update: implement asynchronous decision-making methods in Optimizely and OptimizelyUserContext with corresponding tests * update: refactor DefaultCmabService to remove CmabServiceOptions dependency and adjust related tests * update: refactor DefaultCmabService to use a generic Cache interface and enhance builder methods for cache configuration * fix to support android-sdk * clean up * update: refactor bucketing logic to remove CMAB handling from DecisionService and adjust tests accordingly * update: introduce CacheWithRemove interface and refactor DefaultCmabService to utilize it * update: implement CacheWithRemove interface in DefaultLRUCache class * update: refactor OptimizelyFactory to remove CMAB cache methods and adjust instance creation logic * update: refactor DefaultCmabService to streamline logger initialization and enhance cache handling logging * update: refactor DefaultCmabService to use Cache interface, enhance cache size and timeout, and remove CacheWithRemove interface * update: change parameter type from DefaultCmabService to CmabService in OptimizelyFactory * update: change parameter type from DefaultCmabService to CmabService in newDefaultInstance method of OptimizelyFactory * update: add missing newline at end of file in multiple classes * update: add missing newline at end of OptimizelyDecisionsCallback.java * update: modify DefaultCmabClient constructor to use default retry configuration * update: add cmabEndpoint handling in DefaultCmabClient and CmabClientConfig * Update core-api/src/main/java/com/optimizely/ab/optimizelydecision/OptimizelyDecisionsCallback.java Co-authored-by: Jae Kim <[email protected]> * update: refactor CmabClientConfig to include cmabEndpoint handling and add factory method * update: add overloaded constructor to DecisionService for improved initialization * update: refactor decision methods in Optimizely for improved CMAB handling and backward compatibility * update: add missing newline at end of Bucketer.java file --------- Co-authored-by: Jae Kim <[email protected]> Co-authored-by: Jae Kim <[email protected]>
1 parent 0215660 commit efbda89

27 files changed

+1666
-338
lines changed

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

Lines changed: 170 additions & 39 deletions
Large diffs are not rendered by default.

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

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,26 @@
1616
*/
1717
package com.optimizely.ab;
1818

19-
import com.optimizely.ab.config.ProjectConfig;
20-
import com.optimizely.ab.odp.ODPManager;
21-
import com.optimizely.ab.odp.ODPSegmentCallback;
22-
import com.optimizely.ab.odp.ODPSegmentOption;
23-
import com.optimizely.ab.optimizelydecision.*;
24-
import org.slf4j.Logger;
25-
import org.slf4j.LoggerFactory;
19+
import java.util.Collections;
20+
import java.util.HashMap;
21+
import java.util.LinkedList;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.concurrent.ConcurrentHashMap;
2625

2726
import javax.annotation.Nonnull;
2827
import javax.annotation.Nullable;
29-
import java.util.*;
30-
import java.util.concurrent.ConcurrentHashMap;
28+
29+
import com.optimizely.ab.annotations.VisibleForTesting;
30+
import com.optimizely.ab.optimizelydecision.OptimizelyDecisionCallback;
31+
import com.optimizely.ab.optimizelydecision.OptimizelyDecisionsCallback;
32+
import org.slf4j.Logger;
33+
import org.slf4j.LoggerFactory;
34+
35+
import com.optimizely.ab.odp.ODPSegmentCallback;
36+
import com.optimizely.ab.odp.ODPSegmentOption;
37+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
38+
import com.optimizely.ab.optimizelydecision.OptimizelyDecision;
3139

3240
public class OptimizelyUserContext {
3341
// OptimizelyForcedDecisionsKey mapped to variationKeys
@@ -42,7 +50,7 @@ public class OptimizelyUserContext {
4250
private List<String> qualifiedSegments;
4351

4452
@Nonnull
45-
private final Optimizely optimizely;
53+
final Optimizely optimizely;
4654

4755
private static final Logger logger = LoggerFactory.getLogger(OptimizelyUserContext.class);
4856

@@ -390,4 +398,44 @@ public String toString() {
390398
", attributes='" + attributes + '\'' +
391399
'}';
392400
}
401+
402+
// sync decision support for android-sdk backward compatibility only
403+
404+
@VisibleForTesting // protected, open for testing only
405+
public OptimizelyDecision decideSync(@Nonnull String key,
406+
@Nonnull List<OptimizelyDecideOption> options) {
407+
return optimizely.decideSync(copy(), key, options);
408+
}
409+
410+
@VisibleForTesting // protected, open for testing only
411+
public Map<String, OptimizelyDecision> decideForKeysSync(@Nonnull List<String> keys,
412+
@Nonnull List<OptimizelyDecideOption> options) {
413+
return optimizely.decideForKeysSync(copy(), keys, options);
414+
}
415+
416+
@VisibleForTesting // protected, open for testing only
417+
public Map<String, OptimizelyDecision> decideAllSync(@Nonnull List<OptimizelyDecideOption> options) {
418+
return optimizely.decideAllSync(copy(), options);
419+
}
420+
421+
@VisibleForTesting // protected, open for testing only
422+
public void decideAsync(@Nonnull String key,
423+
@Nonnull List<OptimizelyDecideOption> options,
424+
@Nonnull OptimizelyDecisionCallback callback) {
425+
optimizely.decideAsync(copy(), key, options, callback);
426+
}
427+
428+
@VisibleForTesting // protected, open for testing only
429+
public void decideForKeysAsync(@Nonnull List<String> keys,
430+
@Nonnull List<OptimizelyDecideOption> options,
431+
@Nonnull OptimizelyDecisionsCallback callback) {
432+
optimizely.decideForKeysAsync(copy(), keys, options, callback);
433+
}
434+
435+
@VisibleForTesting // protected, open for testing only
436+
public void decideAllAsync(@Nonnull List<OptimizelyDecideOption> options,
437+
@Nonnull OptimizelyDecisionsCallback callback) {
438+
optimizely.decideAllAsync(copy(), options, callback);
439+
}
440+
393441
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/****************************************************************************
2+
* Copyright 2025 Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
package com.optimizely.ab.bucketing;
17+
18+
public enum DecisionPath {
19+
WITH_CMAB, // Use CMAB logic
20+
WITHOUT_CMAB // Skip CMAB logic (traditional A/B testing)
21+
}

0 commit comments

Comments
 (0)