Skip to content

Commit 480d1e6

Browse files
author
Vignesh Raja
authored
Add support for v2 endpoint (#14)
* Add objects to aid with payload serialization for v2 impression and conversion events * Add serializers using supported JSON libraries * Add layerId to Experiment and modify tests to accommodate this change * Add EventBuilderV2 * Conditionally use V1 or V2 EventBuilders based on datafile version and fix some tests * Add logic to dispatch POST or GET requests in the Async event dispatcher * Modify JSON parsers to set layerId to null if one doesn't exist * Add support for attributes key in datafile, while maintaining backwards compatibility for dimensions * Bump version * Update changelog
1 parent 523e6bf commit 480d1e6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3964
-218
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
## 0.1.71
2+
3+
- Add support for v2 backend endpoint and datafile
4+
15
## 0.1.70
26

3-
- Adds a `UserExperimentRecord` interface
7+
- Add a `UserExperimentRecord` interface
48
- Implementors will get a chance to save and restore activations during bucketing
59
- Can be used to make bucketing persistent or to keep a bucketing history
610
- Pass implementations to `Optimizely.Builder#withUserExperimentRecord(UserExperimentRecord)` when creating `Optimizely` instances

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.optimizely.ab.event.LogEvent;
3333
import com.optimizely.ab.event.internal.EventBuilder;
3434
import com.optimizely.ab.event.internal.EventBuilderV1;
35+
import com.optimizely.ab.event.internal.EventBuilderV2;
3536
import com.optimizely.ab.internal.ProjectValidationUtils;
3637

3738
import org.slf4j.Logger;
@@ -166,8 +167,8 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,
166167
LogEvent impressionEvent =
167168
eventBuilder.createImpressionEvent(projectConfig, experiment, variation, userId, attributes);
168169
logger.info("Activating user \"{}\" in experiment \"{}\".", userId, experiment.getKey());
169-
logger.debug("Dispatching impression event to URL {} with params {}.", impressionEvent.getEndpointUrl(),
170-
impressionEvent.getRequestParams());
170+
logger.debug("Dispatching impression event to URL {} with params {} and payload \"{}\".",
171+
impressionEvent.getEndpointUrl(), impressionEvent.getRequestParams(), impressionEvent.getBody());
171172
eventHandler.dispatchEvent(impressionEvent);
172173

173174
return variation;
@@ -236,8 +237,8 @@ private void track(@Nonnull String eventName,
236237
}
237238

238239
logger.info("Tracking event \"{}\" for user \"{}\".", eventName, userId);
239-
logger.debug("Dispatching conversion event to URL {} with params {}.", conversionEvent.getEndpointUrl(),
240-
conversionEvent.getRequestParams());
240+
logger.debug("Dispatching conversion event to URL {} with params {} and payload \"{}\".",
241+
conversionEvent.getEndpointUrl(), conversionEvent.getRequestParams(), conversionEvent.getBody());
241242
eventHandler.dispatchEvent(conversionEvent);
242243
}
243244

@@ -476,7 +477,11 @@ public Optimizely build() {
476477
}
477478

478479
if (eventBuilder == null) {
479-
eventBuilder = new EventBuilderV1();
480+
if (projectConfig.getVersion().equals(ProjectConfig.V1)) {
481+
eventBuilder = new EventBuilderV1();
482+
} else {
483+
eventBuilder = new EventBuilderV2();
484+
}
480485
}
481486

482487
if (errorHandler == null) {

core-api/src/main/java/com/optimizely/ab/config/Attribute.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ public class Attribute implements IdKeyMapped {
3535
private final String key;
3636
private final String segmentId;
3737

38+
public Attribute(String id, String key) {
39+
this(id, key, null);
40+
}
41+
3842
@JsonCreator
39-
public Attribute(@JsonProperty("is") String id,
43+
public Attribute(@JsonProperty("id") String id,
4044
@JsonProperty("key") String key,
4145
@JsonProperty("segmentId") String segmentId) {
4246
this.id = id;

core-api/src/main/java/com/optimizely/ab/config/Experiment.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.util.List;
2525
import java.util.Map;
2626

27+
import javax.annotation.Nonnull;
28+
import javax.annotation.Nullable;
2729
import javax.annotation.concurrent.Immutable;
2830

2931
/**
@@ -38,6 +40,7 @@ public class Experiment implements IdKeyMapped {
3840
private final String id;
3941
private final String key;
4042
private final String status;
43+
private final String layerId;
4144
private final String groupId;
4245

4346
private final List<String> audienceIds;
@@ -56,19 +59,27 @@ public class Experiment implements IdKeyMapped {
5659
public Experiment(@JsonProperty("id") String id,
5760
@JsonProperty("key") String key,
5861
@JsonProperty("status") String status,
62+
@JsonProperty("layerId") String layerId,
5963
@JsonProperty("audienceIds") List<String> audienceIds,
6064
@JsonProperty("variations") List<Variation> variations,
6165
@JsonProperty("forcedVariations") Map<String, String> userIdToVariationKeyMap,
6266
@JsonProperty("trafficAllocation") List<TrafficAllocation> trafficAllocation) {
63-
this(id, key, status, audienceIds, variations, userIdToVariationKeyMap, trafficAllocation, "");
67+
this(id, key, status, layerId, audienceIds, variations, userIdToVariationKeyMap, trafficAllocation, "");
6468
}
6569

66-
public Experiment(String id, String key, String status, List<String> audienceIds, List<Variation> variations,
67-
Map<String, String> userIdToVariationKeyMap, List<TrafficAllocation> trafficAllocation,
68-
String groupId) {
70+
public Experiment(@Nonnull String id,
71+
@Nonnull String key,
72+
@Nonnull String status,
73+
@Nullable String layerId,
74+
@Nonnull List<String> audienceIds,
75+
@Nonnull List<Variation> variations,
76+
@Nonnull Map<String, String> userIdToVariationKeyMap,
77+
@Nonnull List<TrafficAllocation> trafficAllocation,
78+
@Nonnull String groupId) {
6979
this.id = id;
7080
this.key = key;
7181
this.status = status;
82+
this.layerId = layerId;
7283
this.audienceIds = Collections.unmodifiableList(audienceIds);
7384
this.variations = Collections.unmodifiableList(variations);
7485
this.trafficAllocation = Collections.unmodifiableList(trafficAllocation);
@@ -90,6 +101,10 @@ public String getStatus() {
90101
return status;
91102
}
92103

104+
public String getLayerId() {
105+
return layerId;
106+
}
107+
93108
public List<String> getAudienceIds() {
94109
return audienceIds;
95110
}

core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
*/
1717
package com.optimizely.ab.config;
1818

19-
import com.fasterxml.jackson.annotation.JsonCreator;
2019
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21-
import com.fasterxml.jackson.annotation.JsonProperty;
2220

2321
import com.optimizely.ab.config.audience.Audience;
2422
import com.optimizely.ab.config.audience.Condition;
@@ -39,6 +37,9 @@
3937
@JsonIgnoreProperties(ignoreUnknown = true)
4038
public class ProjectConfig {
4139

40+
public static final String V1 = "1";
41+
public static final String V2 = "2";
42+
4243
private final String accountId;
4344
private final String projectId;
4445
private final String revision;
@@ -57,16 +58,9 @@ public class ProjectConfig {
5758
private final Map<String, Experiment> experimentIdMapping;
5859
private final Map<String, Group> groupIdMapping;
5960

60-
@JsonCreator
61-
public ProjectConfig(@JsonProperty("accountId") String accountId,
62-
@JsonProperty("projectId") String projectId,
63-
@JsonProperty("version") String version,
64-
@JsonProperty("revision") String revision,
65-
@JsonProperty("groups") List<Group> groups,
66-
@JsonProperty("experiments") List<Experiment> experiments,
67-
@JsonProperty("dimensions") List<Attribute> attributes,
68-
@JsonProperty("events") List<EventType> eventType,
69-
@JsonProperty("audiences") List<Audience> audiences) {
61+
public ProjectConfig(String accountId, String projectId, String version, String revision, List<Group> groups,
62+
List<Experiment> experiments, List<Attribute> attributes, List<EventType> eventType,
63+
List<Audience> audiences) {
7064

7165
this.accountId = accountId;
7266
this.projectId = projectId;

core-api/src/main/java/com/optimizely/ab/config/parser/GroupJacksonDeserializer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ private Experiment parseExperiment(JsonNode experimentJson, String groupId) thro
6262
String id = experimentJson.get("id").textValue();
6363
String key = experimentJson.get("key").textValue();
6464
String status = experimentJson.get("status").textValue();
65+
JsonNode layerIdJson = experimentJson.get("layerId");
66+
String layerId = layerIdJson == null ? null : layerIdJson.textValue();
6567
List<String> audienceIds = mapper.readValue(experimentJson.get("audienceIds").toString(),
6668
new TypeReference<List<String>>(){});
6769
List<Variation> variations = mapper.readValue(experimentJson.get("variations").toString(),
@@ -71,8 +73,8 @@ private Experiment parseExperiment(JsonNode experimentJson, String groupId) thro
7173
Map<String, String> userIdToVariationKeyMap = mapper.readValue(
7274
experimentJson.get("forcedVariations").toString(), new TypeReference<Map<String, String>>(){});
7375

74-
return new Experiment(id, key, status, audienceIds, variations, userIdToVariationKeyMap, trafficAllocations,
75-
groupId);
76+
return new Experiment(id, key, status, layerId, audienceIds, variations, userIdToVariationKeyMap,
77+
trafficAllocations, groupId);
7678
}
7779

7880
}

core-api/src/main/java/com/optimizely/ab/config/parser/GsonHelpers.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ static Experiment parseExperiment(JsonObject experimentJson, String groupId) {
7474
String id = experimentJson.get("id").getAsString();
7575
String key = experimentJson.get("key").getAsString();
7676
String status = experimentJson.get("status").getAsString();
77+
JsonElement layerIdJson = experimentJson.get("layerId");
78+
String layerId = layerIdJson == null ? null : layerIdJson.getAsString();
7779

7880
JsonArray audienceIdsJson = experimentJson.getAsJsonArray("audienceIds");
7981
List<String> audienceIds = new ArrayList<String>(audienceIdsJson.size());
@@ -88,8 +90,8 @@ static Experiment parseExperiment(JsonObject experimentJson, String groupId) {
8890
List<TrafficAllocation> trafficAllocations =
8991
parseTrafficAllocation(experimentJson.getAsJsonArray("trafficAllocation"));
9092

91-
return new Experiment(id, key, status, audienceIds, variations, userIdToVariationKeyMap, trafficAllocations,
92-
groupId);
93+
return new Experiment(id, key, status, layerId, audienceIds, variations, userIdToVariationKeyMap,
94+
trafficAllocations, groupId);
9395
}
9496

9597
static Experiment parseExperiment(JsonObject experimentJson) {

core-api/src/main/java/com/optimizely/ab/config/parser/JacksonConfigParser.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
import com.fasterxml.jackson.databind.ObjectMapper;
2020
import com.fasterxml.jackson.databind.module.SimpleModule;
2121

22-
import com.optimizely.ab.config.Group;
23-
import com.optimizely.ab.config.audience.Audience;
2422
import com.optimizely.ab.config.ProjectConfig;
2523

2624
import java.io.IOException;
@@ -36,8 +34,7 @@ final class JacksonConfigParser implements ConfigParser {
3634
public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParseException {
3735
ObjectMapper mapper = new ObjectMapper();
3836
SimpleModule module = new SimpleModule();
39-
module.addDeserializer(Audience.class, new AudienceJacksonDeserializer());
40-
module.addDeserializer(Group.class, new GroupJacksonDeserializer());
37+
module.addDeserializer(ProjectConfig.class, new ProjectConfigJacksonDeserializer());
4138
mapper.registerModule(module);
4239

4340
try {

core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,14 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
5959
String version = rootObject.getString("version");
6060

6161
List<Experiment> experiments = parseExperiments(rootObject.getJSONArray("experiments"));
62-
List<Attribute> attributes = parseAttributes(rootObject.getJSONArray("dimensions"));
62+
63+
List<Attribute> attributes;
64+
if (version.equals(ProjectConfig.V1)) {
65+
attributes = parseAttributes(rootObject.getJSONArray("dimensions"));
66+
} else {
67+
attributes = parseAttributes(rootObject.getJSONArray("attributes"));
68+
}
69+
6370
List<EventType> events = parseEvents(rootObject.getJSONArray("events"));
6471
List<Audience> audiences = parseAudiences(rootObject.getJSONArray("audiences"));
6572
List<Group> groups = parseGroups(rootObject.getJSONArray("groups"));
@@ -85,6 +92,7 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
8592
String id = experimentObject.getString("id");
8693
String key = experimentObject.getString("key");
8794
String status = experimentObject.getString("status");
95+
String layerId = experimentObject.has("layerId") ? experimentObject.getString("layerId") : null;
8896

8997
JSONArray audienceIdsJson = experimentObject.getJSONArray("audienceIds");
9098
List<String> audienceIds = new ArrayList<String>(audienceIdsJson.length());
@@ -100,7 +108,7 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
100108
List<TrafficAllocation> trafficAllocations =
101109
parseTrafficAllocation(experimentObject.getJSONArray("trafficAllocation"));
102110

103-
experiments.add(new Experiment(id, key, status, audienceIds, variations, userIdToVariationKeyMap,
111+
experiments.add(new Experiment(id, key, status, layerId, audienceIds, variations, userIdToVariationKeyMap,
104112
trafficAllocations, groupId));
105113
}
106114

@@ -153,9 +161,8 @@ private List<Attribute> parseAttributes(JSONArray attributeJson) {
153161
JSONObject attributeObject = (JSONObject)obj;
154162
String id = attributeObject.getString("id");
155163
String key = attributeObject.getString("key");
156-
String segmentId = attributeObject.getString("segmentId");
157164

158-
attributes.add(new Attribute(id, key, segmentId));
165+
attributes.add(new Attribute(id, key, attributeObject.optString("segmentId", null)));
159166
}
160167

161168
return attributes;

core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,14 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
6161
String version = (String)rootObject.get("version");
6262

6363
List<Experiment> experiments = parseExperiments((JSONArray)rootObject.get("experiments"));
64-
List<Attribute> attributes = parseAttributes((JSONArray)rootObject.get("dimensions"));
64+
65+
List<Attribute> attributes;
66+
if (version.equals(ProjectConfig.V1)) {
67+
attributes = parseAttributes((JSONArray)rootObject.get("dimensions"));
68+
} else {
69+
attributes = parseAttributes((JSONArray)rootObject.get("attributes"));
70+
}
71+
6572
List<EventType> events = parseEvents((JSONArray)rootObject.get("events"));
6673
List<Audience> audiences = parseAudiences((JSONArray)parser.parse(rootObject.get("audiences").toString()));
6774
List<Group> groups = parseGroups((JSONArray)rootObject.get("groups"));
@@ -87,6 +94,8 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
8794
String id = (String)experimentObject.get("id");
8895
String key = (String)experimentObject.get("key");
8996
String status = (String)experimentObject.get("status");
97+
Object layerIdObject = experimentObject.get("layerId");
98+
String layerId = layerIdObject == null ? null : (String)layerIdObject;
9099

91100
JSONArray audienceIdsJson = (JSONArray)experimentObject.get("audienceIds");
92101
List<String> audienceIds = new ArrayList<String>(audienceIdsJson.size());
@@ -102,7 +111,7 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
102111
List<TrafficAllocation> trafficAllocations =
103112
parseTrafficAllocation((JSONArray)experimentObject.get("trafficAllocation"));
104113

105-
experiments.add(new Experiment(id, key, status, audienceIds, variations, userIdToVariationKeyMap,
114+
experiments.add(new Experiment(id, key, status, layerId, audienceIds, variations, userIdToVariationKeyMap,
106115
trafficAllocations, groupId));
107116
}
108117

0 commit comments

Comments
 (0)