|
17 | 17 |
|
18 | 18 | import com.optimizely.ab.annotations.VisibleForTesting; |
19 | 19 | import com.optimizely.ab.bucketing.*; |
20 | | -import com.optimizely.ab.cmab.service.CmabCacheValue; |
21 | 20 | import com.optimizely.ab.cmab.service.CmabService; |
22 | | -import com.optimizely.ab.cmab.service.DefaultCmabService; |
23 | 21 | import com.optimizely.ab.config.AtomicProjectConfigManager; |
24 | 22 | import com.optimizely.ab.config.DatafileProjectConfig; |
25 | 23 | import com.optimizely.ab.config.EventType; |
@@ -156,7 +154,7 @@ private Optimizely(@Nonnull EventHandler eventHandler, |
156 | 154 | @Nonnull List<OptimizelyDecideOption> defaultDecideOptions, |
157 | 155 | @Nullable ODPManager odpManager, |
158 | 156 | @Nonnull CmabService cmabService |
159 | | - ) { |
| 157 | + ) { |
160 | 158 | this.eventHandler = eventHandler; |
161 | 159 | this.eventProcessor = eventProcessor; |
162 | 160 | this.errorHandler = errorHandler; |
@@ -355,14 +353,14 @@ private boolean sendImpression(@Nonnull ProjectConfig projectConfig, |
355 | 353 |
|
356 | 354 | // Legacy API methods only apply to the Experiment type and not to Holdout. |
357 | 355 | boolean isExperimentType = experiment instanceof Experiment; |
358 | | - |
| 356 | + |
359 | 357 | // Kept For backwards compatibility. |
360 | 358 | // This notification is deprecated and the new DecisionNotifications |
361 | 359 | // are sent via their respective method calls. |
362 | 360 | if (notificationCenter.getNotificationManager(ActivateNotification.class).size() > 0 && isExperimentType) { |
363 | 361 | LogEvent impressionEvent = EventFactory.createLogEvent(userEvent); |
364 | 362 | ActivateNotification activateNotification = new ActivateNotification( |
365 | | - (Experiment)experiment, userId, filteredAttributes, variation, impressionEvent); |
| 363 | + (Experiment) experiment, userId, filteredAttributes, variation, impressionEvent); |
366 | 364 | notificationCenter.send(activateNotification); |
367 | 365 | } |
368 | 366 | return true; |
@@ -1293,20 +1291,6 @@ private OptimizelyUserContext createUserContextCopy(@Nonnull String userId, @Non |
1293 | 1291 | return new OptimizelyUserContext(this, userId, attributes, Collections.EMPTY_MAP, null, false); |
1294 | 1292 | } |
1295 | 1293 |
|
1296 | | - OptimizelyDecision decide(@Nonnull OptimizelyUserContext user, |
1297 | | - @Nonnull String key, |
1298 | | - @Nonnull List<OptimizelyDecideOption> options) { |
1299 | | - ProjectConfig projectConfig = getProjectConfig(); |
1300 | | - if (projectConfig == null) { |
1301 | | - return OptimizelyDecision.newErrorDecision(key, user, DecisionMessage.SDK_NOT_READY.reason()); |
1302 | | - } |
1303 | | - |
1304 | | - List<OptimizelyDecideOption> allOptions = getAllOptions(options); |
1305 | | - allOptions.remove(OptimizelyDecideOption.ENABLED_FLAGS_ONLY); |
1306 | | - |
1307 | | - return decideForKeys(user, Arrays.asList(key), allOptions, true).get(key); |
1308 | | - } |
1309 | | - |
1310 | 1294 | private OptimizelyDecision createOptimizelyDecision( |
1311 | 1295 | OptimizelyUserContext user, |
1312 | 1296 | String flagKey, |
@@ -1397,17 +1381,72 @@ private OptimizelyDecision createOptimizelyDecision( |
1397 | 1381 | reasonsToReport); |
1398 | 1382 | } |
1399 | 1383 |
|
| 1384 | + OptimizelyDecision decide(@Nonnull OptimizelyUserContext user, |
| 1385 | + @Nonnull String key, |
| 1386 | + @Nonnull List<OptimizelyDecideOption> options) { |
| 1387 | + return decideInternal(user, key, options, DecisionPath.WITH_CMAB); |
| 1388 | + } |
| 1389 | + |
1400 | 1390 | Map<String, OptimizelyDecision> decideForKeys(@Nonnull OptimizelyUserContext user, |
1401 | 1391 | @Nonnull List<String> keys, |
1402 | 1392 | @Nonnull List<OptimizelyDecideOption> options) { |
1403 | | - return decideForKeys(user, keys, options, false); |
| 1393 | + return decideForKeysInternal(user, keys, options, false, DecisionPath.WITH_CMAB); |
| 1394 | + } |
| 1395 | + |
| 1396 | + Map<String, OptimizelyDecision> decideAll(@Nonnull OptimizelyUserContext user, |
| 1397 | + @Nonnull List<OptimizelyDecideOption> options) { |
| 1398 | + return decideAllInternal(user, options, DecisionPath.WITH_CMAB); |
| 1399 | + } |
| 1400 | + |
| 1401 | + /** |
| 1402 | + * Returns a decision result ({@link OptimizelyDecision}) for a given flag key and a user context, |
| 1403 | + * skipping CMAB logic and using only traditional A/B testing. |
| 1404 | + * This will be called by mobile apps which will make synchronous decisions only (for backward compatibility with android-sdk) |
| 1405 | + * |
| 1406 | + * @param user An OptimizelyUserContext associated with this OptimizelyClient. |
| 1407 | + * @param key A flag key for which a decision will be made. |
| 1408 | + * @param options A list of options for decision-making. |
| 1409 | + * @return A decision result using traditional A/B testing logic only. |
| 1410 | + */ |
| 1411 | + OptimizelyDecision decideSync(@Nonnull OptimizelyUserContext user, |
| 1412 | + @Nonnull String key, |
| 1413 | + @Nonnull List<OptimizelyDecideOption> options) { |
| 1414 | + return decideInternal(user, key, options, DecisionPath.WITHOUT_CMAB); |
| 1415 | + } |
| 1416 | + |
| 1417 | + /** |
| 1418 | + * Returns decision results for multiple flag keys, skipping CMAB logic and using only traditional A/B testing. |
| 1419 | + * This will be called by mobile apps which will make synchronous decisions only (for backward compatibility with android-sdk) |
| 1420 | + * |
| 1421 | + * @param user An OptimizelyUserContext associated with this OptimizelyClient. |
| 1422 | + * @param keys A list of flag keys for which decisions will be made. |
| 1423 | + * @param options A list of options for decision-making. |
| 1424 | + * @return All decision results mapped by flag keys, using traditional A/B testing logic only. |
| 1425 | + */ |
| 1426 | + Map<String, OptimizelyDecision> decideForKeysSync(@Nonnull OptimizelyUserContext user, |
| 1427 | + @Nonnull List<String> keys, |
| 1428 | + @Nonnull List<OptimizelyDecideOption> options) { |
| 1429 | + return decideForKeysInternal(user, keys, options, false, DecisionPath.WITHOUT_CMAB); |
| 1430 | + } |
| 1431 | + |
| 1432 | + /** |
| 1433 | + * Returns decision results for all active flag keys, skipping CMAB logic and using only traditional A/B testing. |
| 1434 | + * This will be called by mobile apps which will make synchronous decisions only (for backward compatibility with android-sdk) |
| 1435 | + * |
| 1436 | + * @param user An OptimizelyUserContext associated with this OptimizelyClient. |
| 1437 | + * @param options A list of options for decision-making. |
| 1438 | + * @return All decision results mapped by flag keys, using traditional A/B testing logic only. |
| 1439 | + */ |
| 1440 | + Map<String, OptimizelyDecision> decideAllSync(@Nonnull OptimizelyUserContext user, |
| 1441 | + @Nonnull List<OptimizelyDecideOption> options) { |
| 1442 | + return decideAllInternal(user, options, DecisionPath.WITHOUT_CMAB); |
1404 | 1443 | } |
1405 | 1444 |
|
1406 | | - private Map<String, OptimizelyDecision> decideForKeys(@Nonnull OptimizelyUserContext user, |
1407 | | - @Nonnull List<String> keys, |
1408 | | - @Nonnull List<OptimizelyDecideOption> options, |
1409 | | - boolean ignoreDefaultOptions, |
1410 | | - DecisionPath decisionPath) { |
| 1445 | + private Map<String, OptimizelyDecision> decideForKeysInternal(@Nonnull OptimizelyUserContext user, |
| 1446 | + @Nonnull List<String> keys, |
| 1447 | + @Nonnull List<OptimizelyDecideOption> options, |
| 1448 | + boolean ignoreDefaultOptions, |
| 1449 | + DecisionPath decisionPath) { |
1411 | 1450 | Map<String, OptimizelyDecision> decisionMap = new HashMap<>(); |
1412 | 1451 |
|
1413 | 1452 | ProjectConfig projectConfig = getProjectConfig(); |
@@ -1491,28 +1530,85 @@ private Map<String, OptimizelyDecision> decideForKeys(@Nonnull OptimizelyUserCon |
1491 | 1530 | return decisionMap; |
1492 | 1531 | } |
1493 | 1532 |
|
1494 | | - private Map<String, OptimizelyDecision> decideForKeys(@Nonnull OptimizelyUserContext user, |
1495 | | - @Nonnull List<String> keys, |
1496 | | - @Nonnull List<OptimizelyDecideOption> options, |
1497 | | - boolean ignoreDefaultOptions) { |
1498 | | - return decideForKeys(user, keys, options, ignoreDefaultOptions, DecisionPath.WITH_CMAB); |
1499 | | - } |
1500 | | - |
1501 | | - Map<String, OptimizelyDecision> decideAll(@Nonnull OptimizelyUserContext user, |
1502 | | - @Nonnull List<OptimizelyDecideOption> options) { |
| 1533 | + private Map<String, OptimizelyDecision> decideAllInternal(@Nonnull OptimizelyUserContext user, |
| 1534 | + @Nonnull List<OptimizelyDecideOption> options, |
| 1535 | + @Nonnull DecisionPath decisionPath) { |
1503 | 1536 | Map<String, OptimizelyDecision> decisionMap = new HashMap<>(); |
1504 | 1537 |
|
1505 | 1538 | ProjectConfig projectConfig = getProjectConfig(); |
1506 | 1539 | if (projectConfig == null) { |
1507 | | - logger.error("Optimizely instance is not valid, failing isFeatureEnabled call."); |
| 1540 | + logger.error("Optimizely instance is not valid, failing decideAllSync call."); |
1508 | 1541 | return decisionMap; |
1509 | 1542 | } |
1510 | 1543 |
|
1511 | 1544 | List<FeatureFlag> allFlags = projectConfig.getFeatureFlags(); |
1512 | 1545 | List<String> allFlagKeys = new ArrayList<>(); |
1513 | 1546 | for (int i = 0; i < allFlags.size(); i++) allFlagKeys.add(allFlags.get(i).getKey()); |
1514 | 1547 |
|
1515 | | - return decideForKeys(user, allFlagKeys, options); |
| 1548 | + return decideForKeysInternal(user, allFlagKeys, options, false, decisionPath); |
| 1549 | + } |
| 1550 | + |
| 1551 | + private OptimizelyDecision decideInternal(@Nonnull OptimizelyUserContext user, |
| 1552 | + @Nonnull String key, |
| 1553 | + @Nonnull List<OptimizelyDecideOption> options, |
| 1554 | + @Nonnull DecisionPath decisionPath) { |
| 1555 | + ProjectConfig projectConfig = getProjectConfig(); |
| 1556 | + if (projectConfig == null) { |
| 1557 | + return OptimizelyDecision.newErrorDecision(key, user, DecisionMessage.SDK_NOT_READY.reason()); |
| 1558 | + } |
| 1559 | + |
| 1560 | + List<OptimizelyDecideOption> allOptions = getAllOptions(options); |
| 1561 | + allOptions.remove(OptimizelyDecideOption.ENABLED_FLAGS_ONLY); |
| 1562 | + |
| 1563 | + return decideForKeysInternal(user, Arrays.asList(key), allOptions, true, decisionPath).get(key); |
| 1564 | + } |
| 1565 | + |
| 1566 | + //============ decide async ============// |
| 1567 | + |
| 1568 | + /** |
| 1569 | + * Returns a decision result asynchronously for a given flag key and a user context. |
| 1570 | + * |
| 1571 | + * @param userContext The user context to make decisions for |
| 1572 | + * @param key A flag key for which a decision will be made |
| 1573 | + * @param callback A callback to invoke when the decision is available |
| 1574 | + * @param options A list of options for decision-making |
| 1575 | + */ |
| 1576 | + void decideAsync(@Nonnull OptimizelyUserContext userContext, |
| 1577 | + @Nonnull String key, |
| 1578 | + @Nonnull List<OptimizelyDecideOption> options, |
| 1579 | + @Nonnull OptimizelyDecisionCallback callback) { |
| 1580 | + AsyncDecisionFetcher fetcher = new AsyncDecisionFetcher(userContext, key, options, callback); |
| 1581 | + fetcher.start(); |
| 1582 | + } |
| 1583 | + |
| 1584 | + /** |
| 1585 | + * Returns decision results asynchronously for multiple flag keys. |
| 1586 | + * |
| 1587 | + * @param userContext The user context to make decisions for |
| 1588 | + * @param keys A list of flag keys for which decisions will be made |
| 1589 | + * @param callback A callback to invoke when decisions are available |
| 1590 | + * @param options A list of options for decision-making |
| 1591 | + */ |
| 1592 | + void decideForKeysAsync(@Nonnull OptimizelyUserContext userContext, |
| 1593 | + @Nonnull List<String> keys, |
| 1594 | + @Nonnull List<OptimizelyDecideOption> options, |
| 1595 | + @Nonnull OptimizelyDecisionsCallback callback) { |
| 1596 | + AsyncDecisionFetcher fetcher = new AsyncDecisionFetcher(userContext, keys, options, callback); |
| 1597 | + fetcher.start(); |
| 1598 | + } |
| 1599 | + |
| 1600 | + /** |
| 1601 | + * Returns decision results asynchronously for all active flag keys. |
| 1602 | + * |
| 1603 | + * @param userContext The user context to make decisions for |
| 1604 | + * @param callback A callback to invoke when decisions are available |
| 1605 | + * @param options A list of options for decision-making |
| 1606 | + */ |
| 1607 | + void decideAllAsync(@Nonnull OptimizelyUserContext userContext, |
| 1608 | + @Nonnull List<OptimizelyDecideOption> options, |
| 1609 | + @Nonnull OptimizelyDecisionsCallback callback) { |
| 1610 | + AsyncDecisionFetcher fetcher = new AsyncDecisionFetcher(userContext, options, callback); |
| 1611 | + fetcher.start(); |
1516 | 1612 | } |
1517 | 1613 |
|
1518 | 1614 | /** |
|
0 commit comments