Skip to content

Release version 1.4.0 #70

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.4.0

January 31, 2017

- Add `sessionId` parameter to `activate` and `track` and include in event payload
- Append datafile `revision` to event payload
- Add support for "Launched" experiment status

## 1.3.0

January 17, 2017
Expand Down
113 changes: 84 additions & 29 deletions core-api/src/main/java/com/optimizely/ab/Optimizely.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,22 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,
return activate(experimentKey, userId, Collections.<String, String>emptyMap());
}

public @Nullable Variation activate(@Nonnull String experimentKey,
@Nonnull String userId,
@CheckForNull String sessionId) throws UnknownExperimentException {
return activate(experimentKey, userId, Collections.<String, String>emptyMap(), sessionId);
}

public @Nullable Variation activate(@Nonnull String experimentKey,
@Nonnull String userId,
@Nonnull Map<String, String> attributes) throws UnknownExperimentException {
return activate(experimentKey, userId, attributes, null);
}

public @Nullable Variation activate(@Nonnull String experimentKey,
@Nonnull String userId,
@Nonnull Map<String, String> attributes,
@CheckForNull String sessionId) throws UnknownExperimentException {

if (!validateUserId(userId)) {
logger.info("Not activating user for experiment \"{}\".", experimentKey);
Expand All @@ -135,27 +148,42 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,
return null;
}

return activate(currentConfig, experiment, userId, attributes);
return activate(currentConfig, experiment, userId, attributes, sessionId);
}

public @Nullable Variation activate(@Nonnull Experiment experiment,
@Nonnull String userId) {
return activate(experiment, userId, Collections.<String, String>emptyMap());
}

public @Nullable Variation activate(@Nonnull Experiment experiment,
@Nonnull String userId,
@CheckForNull String sessionId) {
return activate(experiment, userId, Collections.<String, String>emptyMap(), sessionId);
}

public @Nullable Variation activate(@Nonnull Experiment experiment,
@Nonnull String userId,
@Nonnull Map<String, String> attributes) {

return activate(experiment, userId, attributes, null);
}

public @Nullable Variation activate(@Nonnull Experiment experiment,
@Nonnull String userId,
@Nonnull Map<String, String> attributes,
@CheckForNull String sessionId) {

ProjectConfig currentConfig = getProjectConfig();

return activate(currentConfig, experiment, userId, attributes);
return activate(currentConfig, experiment, userId, attributes, sessionId);
}

private @Nullable Variation activate(@Nonnull ProjectConfig projectConfig,
@Nonnull Experiment experiment,
@Nonnull String userId,
@Nonnull Map<String, String> attributes) {
@Nonnull Map<String, String> attributes,
@CheckForNull String sessionId) {
// determine whether all the given attributes are present in the project config. If not, filter out the unknown
// attributes.
attributes = filterAttributes(projectConfig, attributes);
Expand All @@ -172,18 +200,23 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,
return null;
}

LogEvent impressionEvent =
eventBuilder.createImpressionEvent(projectConfig, experiment, variation, userId, attributes);
logger.info("Activating user \"{}\" in experiment \"{}\".", userId, experiment.getKey());
logger.debug("Dispatching impression event to URL {} with params {} and payload \"{}\".",
impressionEvent.getEndpointUrl(), impressionEvent.getRequestParams(), impressionEvent.getBody());
try {
eventHandler.dispatchEvent(impressionEvent);
} catch (Exception e) {
logger.error("Unexpected exception in event dispatcher", e);
}
if (experiment.isRunning()) {
LogEvent impressionEvent = eventBuilder.createImpressionEvent(projectConfig, experiment, variation, userId,
attributes, sessionId);
logger.info("Activating user \"{}\" in experiment \"{}\".", userId, experiment.getKey());
logger.debug(
"Dispatching impression event to URL {} with params {} and payload \"{}\".",
impressionEvent.getEndpointUrl(), impressionEvent.getRequestParams(), impressionEvent.getBody());
try {
eventHandler.dispatchEvent(impressionEvent);
} catch (Exception e) {
logger.error("Unexpected exception in event dispatcher", e);
}

notificationBroadcaster.broadcastExperimentActivated(experiment, userId, attributes, variation);
notificationBroadcaster.broadcastExperimentActivated(experiment, userId, attributes, variation);
} else {
logger.info("Experiment has \"Launched\" status so not dispatching event during activation.");
}

return variation;
}
Expand All @@ -192,13 +225,26 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,

public void track(@Nonnull String eventName,
@Nonnull String userId) throws UnknownEventTypeException {
track(eventName, userId, Collections.<String, String>emptyMap(), null);
track(eventName, userId, Collections.<String, String>emptyMap(), null, null);
}

public void track(@Nonnull String eventName,
@Nonnull String userId,
@CheckForNull String sessionId) throws UnknownEventTypeException {
track(eventName, userId, Collections.<String, String>emptyMap(), null, sessionId);
}

public void track(@Nonnull String eventName,
@Nonnull String userId,
@Nonnull Map<String, String> attributes) throws UnknownEventTypeException {
track(eventName, userId, attributes, null);
track(eventName, userId, attributes, null, null);
}

public void track(@Nonnull String eventName,
@Nonnull String userId,
@Nonnull Map<String, String> attributes,
@CheckForNull String sessionId) throws UnknownEventTypeException {
track(eventName, userId, attributes, null, sessionId);
}

public void track(@Nonnull String eventName,
Expand All @@ -207,17 +253,33 @@ public void track(@Nonnull String eventName,
track(eventName, userId, Collections.<String, String>emptyMap(), eventValue);
}

public void track(@Nonnull String eventName,
@Nonnull String userId,
long eventValue,
@CheckForNull String sessionId) throws UnknownEventTypeException {
track(eventName, userId, Collections.<String, String>emptyMap(), eventValue, sessionId);
}

public void track(@Nonnull String eventName,
@Nonnull String userId,
@Nonnull Map<String, String> attributes,
long eventValue) throws UnknownEventTypeException {
track(eventName, userId, attributes, (Long)eventValue);
track(eventName, userId, attributes, (Long)eventValue, null);
}

public void track(@Nonnull String eventName,
@Nonnull String userId,
@Nonnull Map<String, String> attributes,
long eventValue,
@CheckForNull String sessionId) throws UnknownEventTypeException {
track(eventName, userId, attributes, (Long)eventValue, sessionId);
}

private void track(@Nonnull String eventName,
@Nonnull String userId,
@Nonnull Map<String, String> attributes,
@CheckForNull Long eventValue) throws UnknownEventTypeException {
@CheckForNull Long eventValue,
@CheckForNull String sessionId) throws UnknownEventTypeException {

ProjectConfig currentConfig = getProjectConfig();

Expand All @@ -233,16 +295,9 @@ private void track(@Nonnull String eventName,
attributes = filterAttributes(currentConfig, attributes);

// create the conversion event request parameters, then dispatch
LogEvent conversionEvent;
if (eventValue == null) {
conversionEvent = eventBuilder.createConversionEvent(currentConfig, bucketer, userId,
eventType.getId(), eventType.getKey(),
attributes);
} else {
conversionEvent = eventBuilder.createConversionEvent(currentConfig, bucketer, userId,
eventType.getId(), eventType.getKey(), attributes,
eventValue);
}
LogEvent conversionEvent = eventBuilder.createConversionEvent(currentConfig, bucketer, userId,
eventType.getId(), eventType.getKey(), attributes,
eventValue, sessionId);

if (conversionEvent == null) {
logger.info("There are no valid experiments for event \"{}\" to track.", eventName);
Expand All @@ -260,7 +315,7 @@ private void track(@Nonnull String eventName,
}

notificationBroadcaster.broadcastEventTracked(eventName, userId, attributes, eventValue,
conversionEvent);
conversionEvent);
}

//======== live variable getters ========//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public void cleanUserProfiles() {
for (Map.Entry<String,Map<String,String>> record : records.entrySet()) {
for (String experimentId : record.getValue().keySet()) {
Experiment experiment = projectConfig.getExperimentIdMapping().get(experimentId);
if (experiment == null || !experiment.isRunning()) {
if (experiment == null || !experiment.isActive()) {
userProfile.remove(record.getKey(), experimentId);
}
}
Expand Down
31 changes: 27 additions & 4 deletions core-api/src/main/java/com/optimizely/ab/config/Experiment.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,23 @@ public class Experiment implements IdKeyMapped {
private final Map<String, Variation> variationIdToVariationMap;
private final Map<String, String> userIdToVariationKeyMap;

// constant storing the status of a running experiment. Other possible statuses for an experiment
// include 'Not started', 'Paused', and 'Archived'
private static final String STATUS_RUNNING = "Running";
public enum ExperimentStatus {
RUNNING ("Running"),
LAUNCHED ("Launched"),
PAUSED ("Paused"),
NOT_STARTED ("Not started"),
ARCHIVED ("Archived");

private final String experimentStatus;

ExperimentStatus(String experimentStatus) {
this.experimentStatus = experimentStatus;
}

public String toString() {
return experimentStatus;
}
}

@JsonCreator
public Experiment(@JsonProperty("id") String id,
Expand Down Expand Up @@ -133,8 +147,17 @@ public String getGroupId() {
return groupId;
}

public boolean isActive() {
return status.equals(ExperimentStatus.RUNNING.toString()) ||
status.equals(ExperimentStatus.LAUNCHED.toString());
}

public boolean isRunning() {
return status.equals(STATUS_RUNNING);
return status.equals(ExperimentStatus.RUNNING.toString());
}

public boolean isLaunched() {
return status.equals(ExperimentStatus.LAUNCHED.toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,28 @@

public abstract class EventBuilder {

public LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Experiment activatedExperiment,
@Nonnull Variation variation,
@Nonnull String userId,
@Nonnull Map<String, String> attributes) {
return createImpressionEvent(projectConfig, activatedExperiment, variation, userId, attributes, null);
}

public abstract LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Experiment activatedExperiment,
@Nonnull Variation variation,
@Nonnull String userId,
@Nonnull Map<String, String> attributes);
@Nonnull Map<String, String> attributes,
@CheckForNull String sessionId);

public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Bucketer bucketer,
@Nonnull String userId,
@Nonnull String eventId,
@Nonnull String eventName,
@Nonnull Map<String, String> attributes) {
return createConversionEvent(projectConfig, bucketer, userId, eventId, eventName, attributes, null);
return createConversionEvent(projectConfig, bucketer, userId, eventId, eventName, attributes, null, null);
}

public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
Expand All @@ -51,14 +60,16 @@ public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull String eventName,
@Nonnull Map<String, String> attributes,
long eventValue) {
return createConversionEvent(projectConfig, bucketer, userId, eventId, eventName, attributes, (Long)eventValue);
return createConversionEvent(projectConfig, bucketer, userId, eventId, eventName, attributes, (Long)eventValue,
null);
}

abstract LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Bucketer bucketer,
@Nonnull String userId,
@Nonnull String eventId,
@Nonnull String eventName,
@Nonnull Map<String, String> attributes,
@CheckForNull Long eventValue);
public abstract LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Bucketer bucketer,
@Nonnull String userId,
@Nonnull String eventId,
@Nonnull String eventName,
@Nonnull Map<String, String> attributes,
@CheckForNull Long eventValue,
@CheckForNull String sessionId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ public LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Experiment activatedExperiment,
@Nonnull Variation variation,
@Nonnull String userId,
@Nonnull Map<String, String> attributes) {
@Nonnull Map<String, String> attributes,
@CheckForNull String sessionId) {

Map<String, String> requestParams = new HashMap<String, String>();
addCommonRequestParams(requestParams, projectConfig, userId, attributes);
Expand All @@ -78,13 +79,14 @@ public LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig,
String.format(ENDPOINT_FORMAT, projectConfig.getProjectId()), requestParams, EMPTY_BODY);
}

LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Bucketer bucketer,
@Nonnull String userId,
@Nonnull String eventId,
@Nonnull String eventName,
@Nonnull Map<String, String> attributes,
@CheckForNull Long eventValue) {
public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
@Nonnull Bucketer bucketer,
@Nonnull String userId,
@Nonnull String eventId,
@Nonnull String eventName,
@Nonnull Map<String, String> attributes,
@CheckForNull Long eventValue,
@CheckForNull String sessionId) {

Map<String, String> requestParams = new HashMap<String, String>();
List<Experiment> addedExperiments =
Expand Down
Loading