Skip to content

Commit e3a596e

Browse files
Holdouts parsing from data file
1 parent dc44c7e commit e3a596e

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa
5151
}.getType();
5252
Type experimentsType = new TypeToken<List<Experiment>>() {
5353
}.getType();
54+
Type holdoutsType = new TypeToken<List<Holdout>>() {
55+
}.getType();
5456
Type attributesType = new TypeToken<List<Attribute>>() {
5557
}.getType();
5658
Type eventsType = new TypeToken<List<EventType>>() {
@@ -64,6 +66,13 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa
6466
List<Experiment> experiments =
6567
context.deserialize(jsonObject.get("experiments").getAsJsonArray(), experimentsType);
6668

69+
List<Holdout> holdouts;
70+
if (jsonObject.has("holdouts")) {
71+
holdouts = context.deserialize(jsonObject.get("holdouts").getAsJsonArray(), holdoutsType);
72+
} else {
73+
holdouts = Collections.emptyList();
74+
}
75+
6776
List<Attribute> attributes;
6877
attributes = context.deserialize(jsonObject.get("attributes"), attributesType);
6978

@@ -127,6 +136,7 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa
127136
typedAudiences,
128137
events,
129138
experiments,
139+
holdouts,
130140
featureFlags,
131141
groups,
132142
rollouts,

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ public DatafileProjectConfig deserialize(JsonParser parser, DeserializationConte
4646
List<Attribute> attributes = JacksonHelpers.arrayNodeToList(node.get("attributes"), Attribute.class, codec);
4747
List<EventType> events = JacksonHelpers.arrayNodeToList(node.get("events"), EventType.class, codec);
4848

49+
List<Holdout> holdouts;
50+
if (node.has("holdouts")) {
51+
holdouts = JacksonHelpers.arrayNodeToList(node.get("holdouts"), Holdout.class, codec);
52+
} else {
53+
holdouts = Collections.emptyList();
54+
}
55+
4956
List<Audience> audiences = Collections.emptyList();
5057
if (node.has("audiences")) {
5158
audiences = JacksonHelpers.arrayNodeToList(node.get("audiences"), Audience.class, codec);
@@ -103,6 +110,7 @@ public DatafileProjectConfig deserialize(JsonParser parser, DeserializationConte
103110
(List<Audience>) (List<? extends Audience>) typedAudiences,
104111
events,
105112
experiments,
113+
holdouts,
106114
featureFlags,
107115
groups,
108116
rollouts,

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import com.google.gson.reflect.TypeToken;
2626
import com.optimizely.ab.bucketing.DecisionService;
2727
import com.optimizely.ab.config.Experiment;
28+
import com.optimizely.ab.config.Holdout;
2829
import com.optimizely.ab.config.Experiment.ExperimentStatus;
30+
import com.optimizely.ab.config.Holdout.HoldoutStatus;
2931
import com.optimizely.ab.config.FeatureFlag;
3032
import com.optimizely.ab.config.FeatureVariable;
3133
import com.optimizely.ab.config.FeatureVariableUsageInstance;
@@ -151,6 +153,51 @@ static Experiment parseExperiment(JsonObject experimentJson, JsonDeserialization
151153
return parseExperiment(experimentJson, "", context);
152154
}
153155

156+
static Holdout parseHoldout(JsonObject holdoutJson, String groupId, JsonDeserializationContext context) {
157+
String id = holdoutJson.get("id").getAsString();
158+
String key = holdoutJson.get("key").getAsString();
159+
JsonElement holdoutStatusJson = holdoutJson.get("status");
160+
String status = holdoutJson.get("status").getAsString();
161+
162+
JsonArray audienceIdsJson = holdoutJson.getAsJsonArray("audienceIds");
163+
List<String> audienceIds = new ArrayList<>(audienceIdsJson.size());
164+
for (JsonElement audienceIdObj : audienceIdsJson) {
165+
audienceIds.add(audienceIdObj.getAsString());
166+
}
167+
168+
Condition conditions = parseAudienceConditions(holdoutJson);
169+
170+
// parse the child objects
171+
List<Variation> variations = parseVariations(holdoutJson.getAsJsonArray("variations"), context);
172+
Map<String, String> userIdToVariationKeyMap =
173+
parseForcedVariations(holdoutJson.getAsJsonObject("forcedVariations"));
174+
List<TrafficAllocation> trafficAllocations =
175+
parseTrafficAllocation(holdoutJson.getAsJsonArray("trafficAllocation"));
176+
177+
List<String> includedFlags = new ArrayList<>();
178+
if (holdoutJson.has("includedFlags")) {
179+
JsonArray includedIdsJson = holdoutJson.getAsJsonArray("includedFlags");
180+
for (JsonElement hoIdObj : includedIdsJson) {
181+
includedFlags.add(hoIdObj.getAsString());
182+
}
183+
}
184+
185+
List<String> excludedFlags = new ArrayList<>();
186+
if (holdoutJson.has("excludedFlags")) {
187+
JsonArray excludedIdsJson = holdoutJson.getAsJsonArray("excludedFlags");
188+
for (JsonElement hoIdObj : excludedIdsJson) {
189+
excludedFlags.add(hoIdObj.getAsString());
190+
}
191+
}
192+
193+
return new Holdout(id, key, status, audienceIds, conditions, variations, userIdToVariationKeyMap,
194+
trafficAllocations, includedFlags, excludedFlags, groupId);
195+
}
196+
197+
static Holdout parseHoldout(JsonObject holdoutJson, JsonDeserializationContext context) {
198+
return parseHoldout(holdoutJson, "", context);
199+
}
200+
154201
static FeatureFlag parseFeatureFlag(JsonObject featureFlagJson, JsonDeserializationContext context) {
155202
String id = featureFlagJson.get("id").getAsString();
156203
String key = featureFlagJson.get("key").getAsString();

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

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
4848

4949
List<Experiment> experiments = parseExperiments(rootObject.getJSONArray("experiments"));
5050

51+
List<Holdout> holdouts;
52+
if (rootObject.has("holdouts")) {
53+
holdouts = parseHoldouts(rootObject.getJSONArray("holdouts"));
54+
} else {
55+
holdouts = Collections.emptyList();
56+
}
57+
5158
List<Attribute> attributes;
5259
attributes = parseAttributes(rootObject.getJSONArray("attributes"));
5360

@@ -108,6 +115,7 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
108115
typedAudiences,
109116
events,
110117
experiments,
118+
holdouts,
111119
featureFlags,
112120
groups,
113121
rollouts,
@@ -166,6 +174,74 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
166174
return experiments;
167175
}
168176

177+
private List<Holdout> parseHoldouts(JSONArray holdoutJson) {
178+
return parseHoldouts(holdoutJson, "");
179+
}
180+
181+
private List<Holdout> parseHoldouts(JSONArray holdoutJson, String groupId) {
182+
List<Holdout> holdouts = new ArrayList<Holdout>(holdoutJson.length());
183+
184+
for (int i = 0; i < holdoutJson.length(); i++) {
185+
Object obj = holdoutJson.get(i);
186+
JSONObject holdoutObject = (JSONObject) obj;
187+
String id = holdoutObject.getString("id");
188+
String key = holdoutObject.getString("key");
189+
String status = holdoutObject.getString("status");
190+
191+
JSONArray audienceIdsJson = holdoutObject.getJSONArray("audienceIds");
192+
List<String> audienceIds = new ArrayList<String>(audienceIdsJson.length());
193+
194+
for (int j = 0; j < audienceIdsJson.length(); j++) {
195+
Object audienceIdObj = audienceIdsJson.get(j);
196+
audienceIds.add((String) audienceIdObj);
197+
}
198+
199+
Condition conditions = null;
200+
if (holdoutObject.has("audienceConditions")) {
201+
Object jsonCondition = holdoutObject.get("audienceConditions");
202+
conditions = ConditionUtils.<AudienceIdCondition>parseConditions(AudienceIdCondition.class, jsonCondition);
203+
}
204+
205+
// parse the child objects
206+
List<Variation> variations = parseVariations(holdoutObject.getJSONArray("variations"));
207+
Map<String, String> userIdToVariationKeyMap =
208+
parseForcedVariations(holdoutObject.getJSONObject("forcedVariations"));
209+
List<TrafficAllocation> trafficAllocations =
210+
parseTrafficAllocation(holdoutObject.getJSONArray("trafficAllocation"));
211+
212+
List<String> includedFlags;
213+
if (holdoutObject.has("includedFlags")) {
214+
JSONArray includedIdsJson = holdoutObject.getJSONArray("includedFlags");
215+
includedFlags = new ArrayList<>(includedIdsJson.length());
216+
217+
for (int j = 0; j < includedIdsJson.length(); j++) {
218+
Object idObj = includedIdsJson.get(j);
219+
includedFlags.add((String) idObj);
220+
}
221+
} else {
222+
includedFlags = Collections.emptyList();
223+
}
224+
225+
List<String> excludedFlags;
226+
if (holdoutObject.has("excludedFlags")) {
227+
JSONArray excludedIdsJson = holdoutObject.getJSONArray("excludedFlags");
228+
excludedFlags = new ArrayList<>(excludedIdsJson.length());
229+
230+
for (int j = 0; j < excludedIdsJson.length(); j++) {
231+
Object idObj = excludedIdsJson.get(j);
232+
excludedFlags.add((String) idObj);
233+
}
234+
} else {
235+
excludedFlags = Collections.emptyList();
236+
}
237+
238+
holdouts.add(new Holdout(id, key, status, audienceIds, conditions, variations, userIdToVariationKeyMap,
239+
trafficAllocations, includedFlags, excludedFlags, groupId));
240+
}
241+
242+
return holdouts;
243+
}
244+
169245
private List<String> parseExperimentIds(JSONArray experimentIdsJson) {
170246
ArrayList<String> experimentIds = new ArrayList<String>(experimentIdsJson.length());
171247

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
5757

5858
List<Experiment> experiments = parseExperiments((JSONArray) rootObject.get("experiments"));
5959

60+
List<Holdout> holdouts;
61+
if (rootObject.containsKey("holdouts")) {
62+
holdouts = parseHoldouts((JSONArray) rootObject.get("holdouts"));
63+
} else {
64+
holdouts = Collections.emptyList();
65+
}
66+
6067
List<Attribute> attributes;
6168
attributes = parseAttributes((JSONArray) rootObject.get("attributes"));
6269

@@ -111,6 +118,7 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
111118
typedAudiences,
112119
events,
113120
experiments,
121+
holdouts,
114122
featureFlags,
115123
groups,
116124
rollouts,
@@ -173,6 +181,65 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
173181
return experiments;
174182
}
175183

184+
185+
private List<Holdout> parseHoldouts(JSONArray holdoutJson) {
186+
return parseHoldouts(holdoutJson, "");
187+
}
188+
189+
private List<Holdout> parseHoldouts(JSONArray holdoutJson, String groupId) {
190+
List<Holdout> holdouts = new ArrayList<Holdout>(holdoutJson.size());
191+
192+
for (Object obj : holdoutJson) {
193+
JSONObject hoObject = (JSONObject) obj;
194+
String id = (String) hoObject.get("id");
195+
String key = (String) hoObject.get("key");
196+
String status = (String) hoObject.get("status");
197+
198+
JSONArray audienceIdsJson = (JSONArray) hoObject.get("audienceIds");
199+
List<String> audienceIds = new ArrayList<String>(audienceIdsJson.size());
200+
201+
for (Object audienceIdObj : audienceIdsJson) {
202+
audienceIds.add((String) audienceIdObj);
203+
}
204+
205+
Condition conditions = null;
206+
if (hoObject.containsKey("audienceConditions")) {
207+
Object jsonCondition = hoObject.get("audienceConditions");
208+
try {
209+
conditions = ConditionUtils.<AudienceIdCondition>parseConditions(AudienceIdCondition.class, jsonCondition);
210+
} catch (Exception e) {
211+
// unable to parse conditions.
212+
Logger.getAnonymousLogger().log(Level.ALL, "problem parsing audience conditions", e);
213+
}
214+
}
215+
// parse the child objects
216+
List<Variation> variations = parseVariations((JSONArray) hoObject.get("variations"));
217+
Map<String, String> userIdToVariationKeyMap =
218+
parseForcedVariations((JSONObject) hoObject.get("forcedVariations"));
219+
List<TrafficAllocation> trafficAllocations =
220+
parseTrafficAllocation((JSONArray) hoObject.get("trafficAllocation"));
221+
222+
List<String> includedFlags;
223+
if (hoObject.containsKey("includedFlags")) {
224+
includedFlags = new ArrayList<String>((JSONArray) hoObject.get("includedFlags"));
225+
} else {
226+
includedFlags = Collections.emptyList();
227+
}
228+
229+
List<String> excludedFlags;
230+
if (hoObject.containsKey("excludedFlags")) {
231+
excludedFlags = new ArrayList<String>((JSONArray) hoObject.get("excludedFlags"));
232+
} else {
233+
excludedFlags = Collections.emptyList();
234+
}
235+
236+
holdouts.add(new Holdout(id, key, status, audienceIds, conditions, variations, userIdToVariationKeyMap,
237+
trafficAllocations, includedFlags, excludedFlags, groupId));
238+
}
239+
240+
return holdouts;
241+
}
242+
176243
private List<String> parseExperimentIds(JSONArray experimentIdsJsonArray) {
177244
List<String> experimentIds = new ArrayList<String>(experimentIdsJsonArray.size());
178245

0 commit comments

Comments
 (0)