Search in sources :

Example 6 with DecisionReasons

use of com.optimizely.ab.optimizelydecision.DecisionReasons in project java-sdk by optimizely.

the class DecisionService method getVariationForFeature.

/**
 * Get the variation the user is bucketed into for the FeatureFlag
 *
 * @param featureFlag        The feature flag the user wants to access.
 * @param user               The current OptimizelyuserContext
 * @param projectConfig      The current projectConfig
 * @param options            An array of decision options
 * @return A {@link DecisionResponse} including a {@link FeatureDecision} and the decision reasons
 */
@Nonnull
public DecisionResponse<FeatureDecision> getVariationForFeature(@Nonnull FeatureFlag featureFlag, @Nonnull OptimizelyUserContext user, @Nonnull ProjectConfig projectConfig, @Nonnull List<OptimizelyDecideOption> options) {
    DecisionReasons reasons = DefaultDecisionReasons.newInstance();
    DecisionResponse<FeatureDecision> decisionVariationResponse = getVariationFromExperiment(projectConfig, featureFlag, user, options);
    reasons.merge(decisionVariationResponse.getReasons());
    FeatureDecision decision = decisionVariationResponse.getResult();
    if (decision != null) {
        return new DecisionResponse(decision, reasons);
    }
    DecisionResponse<FeatureDecision> decisionFeatureResponse = getVariationForFeatureInRollout(featureFlag, user, projectConfig);
    reasons.merge(decisionFeatureResponse.getReasons());
    decision = decisionFeatureResponse.getResult();
    String message;
    if (decision.variation == null) {
        message = reasons.addInfo("The user \"%s\" was not bucketed into a rollout for feature flag \"%s\".", user.getUserId(), featureFlag.getKey());
    } else {
        message = reasons.addInfo("The user \"%s\" was bucketed into a rollout for feature flag \"%s\".", user.getUserId(), featureFlag.getKey());
    }
    logger.info(message);
    return new DecisionResponse(decision, reasons);
}
Also used : DecisionResponse(com.optimizely.ab.optimizelydecision.DecisionResponse) DefaultDecisionReasons(com.optimizely.ab.optimizelydecision.DefaultDecisionReasons) DecisionReasons(com.optimizely.ab.optimizelydecision.DecisionReasons) Nonnull(javax.annotation.Nonnull)

Example 7 with DecisionReasons

use of com.optimizely.ab.optimizelydecision.DecisionReasons in project java-sdk by optimizely.

the class DecisionService method getVariationForFeatureInRollout.

/**
 * Try to bucket the user into a rollout rule.
 * Evaluate the user for rules in priority order by seeing if the user satisfies the audience.
 * Fall back onto the everyone else rule if the user is ever excluded from a rule due to traffic allocation.
 *
 * @param featureFlag        The feature flag the user wants to access.
 * @param user               The current OptimizelyUserContext
 * @param projectConfig      The current projectConfig
 * @return A {@link DecisionResponse} including a {@link FeatureDecision} and the decision reasons
 */
@Nonnull
DecisionResponse<FeatureDecision> getVariationForFeatureInRollout(@Nonnull FeatureFlag featureFlag, @Nonnull OptimizelyUserContext user, @Nonnull ProjectConfig projectConfig) {
    DecisionReasons reasons = DefaultDecisionReasons.newInstance();
    // use rollout to get variation for feature
    if (featureFlag.getRolloutId().isEmpty()) {
        String message = reasons.addInfo("The feature flag \"%s\" is not used in a rollout.", featureFlag.getKey());
        logger.info(message);
        return new DecisionResponse(new FeatureDecision(null, null, null), reasons);
    }
    Rollout rollout = projectConfig.getRolloutIdMapping().get(featureFlag.getRolloutId());
    if (rollout == null) {
        String message = reasons.addInfo("The rollout with id \"%s\" was not found in the datafile for feature flag \"%s\".", featureFlag.getRolloutId(), featureFlag.getKey());
        logger.error(message);
        return new DecisionResponse(new FeatureDecision(null, null, null), reasons);
    }
    // for all rules before the everyone else rule
    int rolloutRulesLength = rollout.getExperiments().size();
    if (rolloutRulesLength == 0) {
        return new DecisionResponse(new FeatureDecision(null, null, null), reasons);
    }
    int index = 0;
    while (index < rolloutRulesLength) {
        DecisionResponse<AbstractMap.SimpleEntry> decisionVariationResponse = getVariationFromDeliveryRule(projectConfig, featureFlag.getKey(), rollout.getExperiments(), index, user);
        reasons.merge(decisionVariationResponse.getReasons());
        AbstractMap.SimpleEntry<Variation, Boolean> response = decisionVariationResponse.getResult();
        Variation variation = response.getKey();
        Boolean skipToEveryoneElse = response.getValue();
        if (variation != null) {
            Experiment rule = rollout.getExperiments().get(index);
            FeatureDecision featureDecision = new FeatureDecision(rule, variation, FeatureDecision.DecisionSource.ROLLOUT);
            return new DecisionResponse(featureDecision, reasons);
        }
        // The last rule is special for "Everyone Else"
        index = skipToEveryoneElse ? (rolloutRulesLength - 1) : (index + 1);
    }
    return new DecisionResponse(new FeatureDecision(null, null, null), reasons);
}
Also used : DecisionResponse(com.optimizely.ab.optimizelydecision.DecisionResponse) DefaultDecisionReasons(com.optimizely.ab.optimizelydecision.DefaultDecisionReasons) DecisionReasons(com.optimizely.ab.optimizelydecision.DecisionReasons) Nonnull(javax.annotation.Nonnull)

Example 8 with DecisionReasons

use of com.optimizely.ab.optimizelydecision.DecisionReasons in project java-sdk by optimizely.

the class ExperimentUtils method evaluateAudience.

@Nonnull
public static DecisionResponse<Boolean> evaluateAudience(@Nonnull ProjectConfig projectConfig, @Nonnull Experiment experiment, @Nonnull Map<String, ?> attributes, @Nonnull String loggingEntityType, @Nonnull String loggingKey) {
    DecisionReasons reasons = DefaultDecisionReasons.newInstance();
    List<String> experimentAudienceIds = experiment.getAudienceIds();
    // if there are no audiences, ALL users should be part of the experiment
    if (experimentAudienceIds.isEmpty()) {
        return new DecisionResponse(true, reasons);
    }
    List<Condition> conditions = new ArrayList<>();
    for (String audienceId : experimentAudienceIds) {
        AudienceIdCondition condition = new AudienceIdCondition(audienceId);
        conditions.add(condition);
    }
    OrCondition implicitOr = new OrCondition(conditions);
    logger.debug("Evaluating audiences for {} \"{}\": {}.", loggingEntityType, loggingKey, conditions);
    Boolean result = implicitOr.evaluate(projectConfig, attributes);
    String message = reasons.addInfo("Audiences for %s \"%s\" collectively evaluated to %s.", loggingEntityType, loggingKey, result);
    logger.info(message);
    return new DecisionResponse(result, reasons);
}
Also used : Condition(com.optimizely.ab.config.audience.Condition) OrCondition(com.optimizely.ab.config.audience.OrCondition) AudienceIdCondition(com.optimizely.ab.config.audience.AudienceIdCondition) DecisionResponse(com.optimizely.ab.optimizelydecision.DecisionResponse) AudienceIdCondition(com.optimizely.ab.config.audience.AudienceIdCondition) ArrayList(java.util.ArrayList) OrCondition(com.optimizely.ab.config.audience.OrCondition) DefaultDecisionReasons(com.optimizely.ab.optimizelydecision.DefaultDecisionReasons) DecisionReasons(com.optimizely.ab.optimizelydecision.DecisionReasons) Nonnull(javax.annotation.Nonnull)

Example 9 with DecisionReasons

use of com.optimizely.ab.optimizelydecision.DecisionReasons in project java-sdk by optimizely.

the class DecisionService method getForcedVariation.

/**
 * Gets the forced variation for a given user and experiment.
 *
 * @param experiment    The experiment forced.
 * @param userId        The user ID to be used for bucketing.
 * @return A {@link DecisionResponse} including the {@link Variation} that user is bucketed into (or null)
 * and the decision reasons. The variation can be null if the forced variation fails.
 */
@Nonnull
public DecisionResponse<Variation> getForcedVariation(@Nonnull Experiment experiment, @Nonnull String userId) {
    DecisionReasons reasons = DefaultDecisionReasons.newInstance();
    if (!validateUserId(userId)) {
        String message = reasons.addInfo("User ID is invalid");
        logger.error(message);
        return new DecisionResponse(null, reasons);
    }
    Map<String, String> experimentToVariation = getForcedVariationMapping().get(userId);
    if (experimentToVariation != null) {
        String variationId = experimentToVariation.get(experiment.getId());
        if (variationId != null) {
            Variation variation = experiment.getVariationIdToVariationMap().get(variationId);
            if (variation != null) {
                String message = reasons.addInfo("Variation \"%s\" is mapped to experiment \"%s\" and user \"%s\" in the forced variation map", variation.getKey(), experiment.getKey(), userId);
                logger.debug(message);
                return new DecisionResponse(variation, reasons);
            }
        } else {
            logger.debug("No variation for experiment \"{}\" mapped to user \"{}\" in the forced variation map ", experiment.getKey(), userId);
        }
    }
    return new DecisionResponse(null, reasons);
}
Also used : DecisionResponse(com.optimizely.ab.optimizelydecision.DecisionResponse) DefaultDecisionReasons(com.optimizely.ab.optimizelydecision.DefaultDecisionReasons) DecisionReasons(com.optimizely.ab.optimizelydecision.DecisionReasons) Nonnull(javax.annotation.Nonnull)

Example 10 with DecisionReasons

use of com.optimizely.ab.optimizelydecision.DecisionReasons in project java-sdk by optimizely.

the class DecisionService method getWhitelistedVariation.

/**
 * Get the variation the user has been whitelisted into.
 *
 * @param experiment {@link Experiment} in which user is to be bucketed.
 * @param userId     User Identifier
 * @return A {@link DecisionResponse} including the {@link Variation} that user is bucketed into (or null)
 * and the decision reasons. The variation can be null if the user is not whitelisted into any variation.
 */
@Nonnull
DecisionResponse<Variation> getWhitelistedVariation(@Nonnull Experiment experiment, @Nonnull String userId) {
    DecisionReasons reasons = DefaultDecisionReasons.newInstance();
    // if a user has a forced variation mapping, return the respective variation
    Map<String, String> userIdToVariationKeyMap = experiment.getUserIdToVariationKeyMap();
    if (userIdToVariationKeyMap.containsKey(userId)) {
        String forcedVariationKey = userIdToVariationKeyMap.get(userId);
        Variation forcedVariation = experiment.getVariationKeyToVariationMap().get(forcedVariationKey);
        if (forcedVariation != null) {
            String message = reasons.addInfo("User \"%s\" is forced in variation \"%s\".", userId, forcedVariationKey);
            logger.info(message);
        } else {
            String message = reasons.addInfo("Variation \"%s\" is not in the datafile. Not activating user \"%s\".", forcedVariationKey, userId);
            logger.error(message);
        }
        return new DecisionResponse(forcedVariation, reasons);
    }
    return new DecisionResponse(null, reasons);
}
Also used : DecisionResponse(com.optimizely.ab.optimizelydecision.DecisionResponse) DefaultDecisionReasons(com.optimizely.ab.optimizelydecision.DefaultDecisionReasons) DecisionReasons(com.optimizely.ab.optimizelydecision.DecisionReasons) Nonnull(javax.annotation.Nonnull)

Aggregations

DecisionReasons (com.optimizely.ab.optimizelydecision.DecisionReasons)15 DecisionResponse (com.optimizely.ab.optimizelydecision.DecisionResponse)15 DefaultDecisionReasons (com.optimizely.ab.optimizelydecision.DefaultDecisionReasons)15 Nonnull (javax.annotation.Nonnull)12 OptimizelyDecisionContext (com.optimizely.ab.OptimizelyDecisionContext)2 OptimizelyForcedDecision (com.optimizely.ab.OptimizelyForcedDecision)2 AudienceIdCondition (com.optimizely.ab.config.audience.AudienceIdCondition)2 Condition (com.optimizely.ab.config.audience.Condition)2 OrCondition (com.optimizely.ab.config.audience.OrCondition)2 OptimizelyRuntimeException (com.optimizely.ab.OptimizelyRuntimeException)1 ArrayList (java.util.ArrayList)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1