Skip to content

Commit 4a2f0fa

Browse files
authored
parse rollouts (#135)
* add list of rollouts to ProjectConfig and constructor. Add to all usages of ProjectConfig v4 constructor to allow compilation * add basic rollout to v4 json and V4 project config * enable Jackson to parse rollouts * enable GSON parsing for rollouts * enable parsing for org.JSON * enable json simple parsing * remove Layer.java class and remove 'policy' property of a Rollout * rollout experiment and variation keys will be the same as id
1 parent 9e9fd9f commit 4a2f0fa

File tree

10 files changed

+194
-92
lines changed

10 files changed

+194
-92
lines changed

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

Lines changed: 0 additions & 71 deletions
This file was deleted.

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

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public String toString() {
6666
private final List<FeatureFlag> featureFlags;
6767
private final List<Group> groups;
6868
private final List<LiveVariable> liveVariables;
69+
private final List<Rollout> rollouts;
6970

7071
// key to entity mappings
7172
private final Map<String, Attribute> attributeKeyMapping;
@@ -108,7 +109,8 @@ public ProjectConfig(String accountId, String projectId, String version, String
108109
experiments,
109110
null,
110111
groups,
111-
liveVariables
112+
liveVariables,
113+
null
112114
);
113115
}
114116

@@ -124,7 +126,8 @@ public ProjectConfig(String accountId,
124126
List<Experiment> experiments,
125127
List<FeatureFlag> featureFlags,
126128
List<Group> groups,
127-
List<LiveVariable> liveVariables) {
129+
List<LiveVariable> liveVariables,
130+
List<Rollout> rollouts) {
128131

129132
this.accountId = accountId;
130133
this.projectId = projectId;
@@ -141,6 +144,12 @@ public ProjectConfig(String accountId,
141144
else {
142145
this.featureFlags = Collections.unmodifiableList(featureFlags);
143146
}
147+
if (rollouts == null) {
148+
this.rollouts = Collections.emptyList();
149+
}
150+
else {
151+
this.rollouts = Collections.unmodifiableList(rollouts);
152+
}
144153

145154
this.groups = Collections.unmodifiableList(groups);
146155

@@ -243,6 +252,10 @@ public List<FeatureFlag> getFeatureFlags() {
243252
return featureFlags;
244253
}
245254

255+
public List<Rollout> getRollouts() {
256+
return rollouts;
257+
}
258+
246259
public List<Attribute> getAttributes() {
247260
return attributes;
248261
}
@@ -312,22 +325,26 @@ public String toString() {
312325
", projectId='" + projectId + '\'' +
313326
", revision='" + revision + '\'' +
314327
", version='" + version + '\'' +
315-
", anonymizeIP='" + anonymizeIP + '\'' +
316-
", groups=" + groups +
317-
", experiments=" + experiments +
328+
", anonymizeIP=" + anonymizeIP +
318329
", attributes=" + attributes +
319-
", events=" + events +
320330
", audiences=" + audiences +
331+
", events=" + events +
332+
", experiments=" + experiments +
333+
", featureFlags=" + featureFlags +
334+
", groups=" + groups +
321335
", liveVariables=" + liveVariables +
322-
", experimentKeyMapping=" + experimentKeyMapping +
336+
", rollouts=" + rollouts +
323337
", attributeKeyMapping=" + attributeKeyMapping +
324-
", liveVariableKeyMapping=" + liveVariableKeyMapping +
325338
", eventNameMapping=" + eventNameMapping +
339+
", experimentKeyMapping=" + experimentKeyMapping +
340+
", featureKeyMapping=" + featureKeyMapping +
341+
", liveVariableKeyMapping=" + liveVariableKeyMapping +
326342
", audienceIdMapping=" + audienceIdMapping +
327343
", experimentIdMapping=" + experimentIdMapping +
328344
", groupIdMapping=" + groupIdMapping +
329345
", liveVariableIdToExperimentsMapping=" + liveVariableIdToExperimentsMapping +
330346
", variationToLiveVariableUsageInstanceMapping=" + variationToLiveVariableUsageInstanceMapping +
347+
", variationIdToExperimentMapping=" + variationIdToExperimentMapping +
331348
'}';
332349
}
333350
}

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

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

19+
import com.fasterxml.jackson.annotation.JsonCreator;
20+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21+
import com.fasterxml.jackson.annotation.JsonProperty;
22+
1923
import javax.annotation.concurrent.Immutable;
2024
import java.util.List;
2125

@@ -25,19 +29,32 @@
2529
* @see <a href="http://developers.optimizely.com/server/reference/index.html#json">Project JSON</a>
2630
*/
2731
@Immutable
28-
public class Rollout extends Layer implements IdMapped {
32+
@JsonIgnoreProperties(ignoreUnknown = true)
33+
public class Rollout implements IdMapped {
34+
35+
private final String id;
36+
private final List<Experiment> experiments;
37+
38+
@JsonCreator
39+
public Rollout(@JsonProperty("id") String id,
40+
@JsonProperty("experiments") List<Experiment> experiments) {
41+
this.id = id;
42+
this.experiments = experiments;
43+
}
44+
45+
@Override
46+
public String getId() {
47+
return id;
48+
}
2949

30-
public Rollout(String id,
31-
String policy,
32-
List<Experiment> experiments) {
33-
super(id, policy, experiments);
50+
public List<Experiment> getExperiments() {
51+
return experiments;
3452
}
3553

3654
@Override
3755
public String toString() {
3856
return "Rollout{" +
3957
"id='" + id + '\'' +
40-
", policy='" + policy + '\'' +
4158
", experiments=" + experiments +
4259
'}';
4360
}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.optimizely.ab.config.LiveVariable.VariableType;
2828
import com.optimizely.ab.config.LiveVariableUsageInstance;
2929
import com.optimizely.ab.config.ProjectConfig;
30+
import com.optimizely.ab.config.Rollout;
3031
import com.optimizely.ab.config.TrafficAllocation;
3132
import com.optimizely.ab.config.Variation;
3233
import com.optimizely.ab.config.audience.AndCondition;
@@ -79,8 +80,10 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
7980
}
8081

8182
List<FeatureFlag> featureFlags = null;
83+
List<Rollout> rollouts = null;
8284
if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) {
8385
featureFlags = parseFeatureFlags(rootObject.getJSONArray("featureFlags"));
86+
rollouts = parseRollouts(rootObject.getJSONArray("rollouts"));
8487
}
8588

8689
return new ProjectConfig(
@@ -95,7 +98,8 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
9598
experiments,
9699
featureFlags,
97100
groups,
98-
liveVariables
101+
liveVariables,
102+
rollouts
99103
);
100104
} catch (Exception e) {
101105
throw new ConfigParseException("Unable to parse datafile: " + json, e);
@@ -344,4 +348,18 @@ private List<LiveVariableUsageInstance> parseLiveVariableInstances(JSONArray liv
344348

345349
return liveVariableUsageInstances;
346350
}
351+
352+
private List<Rollout> parseRollouts(JSONArray rolloutsJson) {
353+
List<Rollout> rollouts = new ArrayList<Rollout>(rolloutsJson.length());
354+
355+
for (Object obj : rolloutsJson) {
356+
JSONObject rolloutObject = (JSONObject) obj;
357+
String id = rolloutObject.getString("id");
358+
List<Experiment> experiments = parseExperiments(rolloutObject.getJSONArray("experiments"));
359+
360+
rollouts.add(new Rollout(id, experiments));
361+
}
362+
363+
return rollouts;
364+
}
347365
}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.optimizely.ab.config.LiveVariable.VariableType;
2828
import com.optimizely.ab.config.LiveVariableUsageInstance;
2929
import com.optimizely.ab.config.ProjectConfig;
30+
import com.optimizely.ab.config.Rollout;
3031
import com.optimizely.ab.config.TrafficAllocation;
3132
import com.optimizely.ab.config.Variation;
3233
import com.optimizely.ab.config.audience.AndCondition;
@@ -81,8 +82,10 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
8182
}
8283

8384
List<FeatureFlag> featureFlags = null;
85+
List<Rollout> rollouts = null;
8486
if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) {
8587
featureFlags = parseFeatureFlags((JSONArray) rootObject.get("featureFlags"));
88+
rollouts = parseRollouts((JSONArray) rootObject.get("rollouts"));
8689
}
8790

8891
return new ProjectConfig(
@@ -97,7 +100,8 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
97100
experiments,
98101
featureFlags,
99102
groups,
100-
liveVariables
103+
liveVariables,
104+
rollouts
101105
);
102106
} catch (Exception e) {
103107
throw new ConfigParseException("Unable to parse datafile: " + json, e);
@@ -348,5 +352,19 @@ private List<LiveVariableUsageInstance> parseLiveVariableInstances(JSONArray liv
348352

349353
return liveVariableUsageInstances;
350354
}
355+
356+
private List<Rollout> parseRollouts(JSONArray rolloutsJson) {
357+
List<Rollout> rollouts = new ArrayList<Rollout>(rolloutsJson.size());
358+
359+
for (Object obj : rolloutsJson) {
360+
JSONObject rolloutObject = (JSONObject) obj;
361+
String id = (String) rolloutObject.get("id");
362+
List<Experiment> experiments = parseExperiments((JSONArray) rolloutObject.get("experiments"));
363+
364+
rollouts.add(new Rollout(id, experiments));
365+
}
366+
367+
return rollouts;
368+
}
351369
}
352370

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.optimizely.ab.config.Group;
3030
import com.optimizely.ab.config.LiveVariable;
3131
import com.optimizely.ab.config.ProjectConfig;
32+
import com.optimizely.ab.config.Rollout;
3233
import com.optimizely.ab.config.audience.Audience;
3334

3435
import java.lang.reflect.Type;
@@ -80,9 +81,12 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa
8081
}
8182

8283
List<FeatureFlag> featureFlags = null;
84+
List<Rollout> rollouts = null;
8385
if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) {
8486
Type featureFlagsType = new TypeToken<List<FeatureFlag>>() {}.getType();
8587
featureFlags = context.deserialize(jsonObject.getAsJsonArray("featureFlags"), featureFlagsType);
88+
Type rolloutsType = new TypeToken<List<Rollout>>() {}.getType();
89+
rollouts = context.deserialize(jsonObject.get("rollouts").getAsJsonArray(), rolloutsType);
8690
}
8791

8892
return new ProjectConfig(
@@ -97,7 +101,8 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa
97101
experiments,
98102
featureFlags,
99103
groups,
100-
liveVariables
104+
liveVariables,
105+
rollouts
101106
);
102107
}
103108
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.optimizely.ab.config.Group;
3131
import com.optimizely.ab.config.LiveVariable;
3232
import com.optimizely.ab.config.ProjectConfig;
33+
import com.optimizely.ab.config.Rollout;
3334
import com.optimizely.ab.config.audience.Audience;
3435

3536
import java.io.IOException;
@@ -74,9 +75,12 @@ public ProjectConfig deserialize(JsonParser parser, DeserializationContext conte
7475
}
7576

7677
List<FeatureFlag> featureFlags = null;
78+
List<Rollout> rollouts = null;
7779
if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) {
7880
featureFlags = mapper.readValue(node.get("featureFlags").toString(),
7981
new TypeReference<List<FeatureFlag>>() {});
82+
rollouts = mapper.readValue(node.get("rollouts").toString(),
83+
new TypeReference<List<Rollout>>(){});
8084
}
8185

8286
return new ProjectConfig(
@@ -91,7 +95,8 @@ public ProjectConfig deserialize(JsonParser parser, DeserializationContext conte
9195
experiments,
9296
featureFlags,
9397
groups,
94-
liveVariables
98+
liveVariables,
99+
rollouts
95100
);
96101
}
97102
}

core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ public static void verifyProjectConfig(@CheckForNull ProjectConfig actual, @Nonn
457457
verifyFeatureFlags(actual.getFeatureFlags(), expected.getFeatureFlags());
458458
verifyLiveVariables(actual.getLiveVariables(), expected.getLiveVariables());
459459
verifyGroups(actual.getGroups(), expected.getGroups());
460+
verifyRollouts(actual.getRollouts(), expected.getRollouts());
460461
}
461462

462463
/**
@@ -617,6 +618,23 @@ private static void verifyLiveVariables(List<LiveVariable> actual, List<LiveVari
617618
}
618619
}
619620

621+
private static void verifyRollouts(List<Rollout> actual, List<Rollout> expected) {
622+
if (expected == null) {
623+
assertNull(actual);
624+
}
625+
else {
626+
assertEquals(expected.size(), actual.size());
627+
628+
for (int i = 0; i < actual.size(); i++) {
629+
Rollout actualRollout = actual.get(i);
630+
Rollout expectedRollout = expected.get(i);
631+
632+
assertEquals(expectedRollout.getId(), actualRollout.getId());
633+
verifyExperiments(actualRollout.getExperiments(), expectedRollout.getExperiments());
634+
}
635+
}
636+
}
637+
620638
/**
621639
* Verify that the provided variation-level live variable usage instances are equivalent.
622640
*/

0 commit comments

Comments
 (0)