All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.glassdoor.planout4j.Namespace Maven / Gradle / Ivy

The newest version!
package com.glassdoor.planout4j;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections4.MapUtils;

import com.glassdoor.planout4j.planout.Interpreter;
import com.glassdoor.planout4j.util.Helper;

import static com.google.common.base.Preconditions.*;

/**
 * Namespace represents an instance of traffic segmentation for experiments management.
 * Multiple namespaces segment traffic independently.
 * A unit (such as user GUID) can be part of a single experiment within a namespace,
 * but in multiple experiments in different namespaces.
* The experiment's parameters assignment will be eagerly evaluated and cached. * @author ernest.mishkin */ public class Namespace { /** * When present in the input map with {@link Boolean#TRUE} as the value, * the system will use default experiment and not attempt to allocate the unit to a segment. *

This is used to indicate traffic from bots, partner apps, etc. */ public static final String BASELINE_KEY = "_baseline_"; // at this point NamespaceConfig is immutable, so it's safe to expose it public final NamespaceConfig nsConf; private Experiment experiment; private Map assignments; /** * Constructs new namespace. Verifies the input is sane (has entry for the primary unit). * Evaluates the assignments and caches the result. * @param nsConf Namespace configuration * @param input Map of string parameter names to parameter values * @param overrides override parameter names/values to enable "freezing" * certain computed parameters, e.g. via query string; optional */ public Namespace(final NamespaceConfig nsConf, final Map input, final Map overrides) { checkArgument(nsConf != null, "nsConf is required"); checkArgument(MapUtils.isNotEmpty(input), "input map cannot be null or empty"); this.nsConf = nsConf; makeAssignments(input, overrides); } /** * @return Cached (eagerly evaluated) Map of parameter assignments */ public Map getParams() { return assignments; } /** * @return name of the namespace */ public String getName() { return nsConf.name; } /** * @return The active experiment for the specified input */ public Experiment getExperiment() { return experiment; } /** * Responsible for evaluating the experiment in the context of the given input and overrides. * @param input input context * @param overrides optional overrides (to freeze certain output parameters) * @return result of making assignments as per the experiment script. */ protected Map evaluateExperiment(final Experiment exp, final Map input, final Map overrides) { final Map _input = Helper.cast(input), _overrides = Helper.cast(overrides); return Collections.unmodifiableMap(new Interpreter(exp.def.getCopyOfScript(), exp.salt, _input, _overrides).getParams()); } private void makeAssignments(final Map input, final Map overrides) { final Experiment defaultExperiment = nsConf.getDefaultExperiment(); // "compiler" ensures that default experiment is present, so it's safe to fail-fast here checkState(defaultExperiment != null, "Default experiment not set in %s namespace", nsConf.name); final Map defaultAssignments = evaluateExperiment(defaultExperiment, input, overrides); if (isBaseline(input)) { assignments = defaultAssignments; } else { experiment = nsConf.getExperiment(input); if (experiment != null) { Map tmp = new HashMap<>(defaultAssignments); // the tmp trick is due to generics issues final Map specificAssignments = evaluateExperiment(experiment, input, overrides); tmp.putAll(specificAssignments); assignments = tmp; } else { assignments = defaultAssignments; } } } protected boolean isBaseline(final Map input) { final Object baseline = input.get(BASELINE_KEY); return baseline instanceof Boolean && (Boolean)baseline; } public int getParam(final String key, final int def) { return getParams().containsKey(key) ? ((Number)getParams().get(key)).intValue() : def; } public float getParam(final String key, final float def) { return getParams().containsKey(key) ? ((Number)getParams().get(key)).floatValue() : def; } public boolean getParam(final String key, final boolean def) { return getParams().containsKey(key) ? ((Boolean)getParams().get(key)) : def; } public String getParam(final String key, final String def) { return getParams().containsKey(key) ? ((String)getParams().get(key)) : def; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy