Skip to content

Commit 2640eaa

Browse files
Cmab datafile parsed
1 parent f90da0c commit 2640eaa

File tree

6 files changed

+193
-15
lines changed

6 files changed

+193
-15
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
*
3+
* Copyright 2025 Optimizely and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.optimizely.ab.config;
18+
19+
import java.util.List;
20+
import java.util.Objects;
21+
22+
import com.fasterxml.jackson.annotation.JsonCreator;
23+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
24+
import com.fasterxml.jackson.annotation.JsonProperty;
25+
/**
26+
* Represents the Optimizely Traffic Allocation configuration.
27+
*
28+
* @see <a href="http://developers.optimizely.com/server/reference/index.html#json">Project JSON</a>
29+
*/
30+
@JsonIgnoreProperties(ignoreUnknown = true)
31+
public class Cmab {
32+
33+
private final List<String> attributeIds;
34+
private final int trafficAllocation;
35+
36+
@JsonCreator
37+
public Cmab(@JsonProperty("attributeIds") List<String> attributeIds,
38+
@JsonProperty("trafficAllocation") int trafficAllocation) {
39+
this.attributeIds = attributeIds;
40+
this.trafficAllocation = trafficAllocation;
41+
}
42+
43+
public List<String> getAttributeIds() {
44+
return attributeIds;
45+
}
46+
47+
public int getTrafficAllocation() {
48+
return trafficAllocation;
49+
}
50+
51+
@Override
52+
public boolean equals(Object obj) {
53+
if (this == obj) return true;
54+
if (obj == null || getClass() != obj.getClass()) return false;
55+
Cmab cmab = (Cmab) obj;
56+
return trafficAllocation == cmab.trafficAllocation &&
57+
Objects.equals(attributeIds, cmab.attributeIds);
58+
}
59+
60+
@Override
61+
public int hashCode() {
62+
return Objects.hash(attributeIds, trafficAllocation);
63+
}
64+
65+
@Override
66+
public String toString() {
67+
return "Cmab{" +
68+
"attributeIds=" + attributeIds +
69+
", trafficAllocation=" + trafficAllocation +
70+
'}';
71+
}
72+
}

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class Experiment implements IdKeyMapped {
4141
private final String status;
4242
private final String layerId;
4343
private final String groupId;
44+
private final Cmab cmab;
4445

4546
private final String AND = "AND";
4647
private final String OR = "OR";
@@ -75,7 +76,25 @@ public String toString() {
7576

7677
@VisibleForTesting
7778
public Experiment(String id, String key, String layerId) {
78-
this(id, key, null, layerId, Collections.emptyList(), null, Collections.emptyList(), Collections.emptyMap(), Collections.emptyList(), "");
79+
this(id, key, null, layerId, Collections.emptyList(), null, Collections.emptyList(), Collections.emptyMap(), Collections.emptyList(), "", null);
80+
}
81+
82+
@VisibleForTesting
83+
public Experiment(String id, String key, String status, String layerId,
84+
List<String> audienceIds, Condition audienceConditions,
85+
List<Variation> variations, Map<String, String> userIdToVariationKeyMap,
86+
List<TrafficAllocation> trafficAllocation, String groupId) {
87+
this(id, key, status, layerId, audienceIds, audienceConditions, variations,
88+
userIdToVariationKeyMap, trafficAllocation, groupId, null); // Default cmab=null
89+
}
90+
91+
@VisibleForTesting
92+
public Experiment(String id, String key, String status, String layerId,
93+
List<String> audienceIds, Condition audienceConditions,
94+
List<Variation> variations, Map<String, String> userIdToVariationKeyMap,
95+
List<TrafficAllocation> trafficAllocation) {
96+
this(id, key, status, layerId, audienceIds, audienceConditions, variations,
97+
userIdToVariationKeyMap, trafficAllocation, "", null); // Default groupId="" and cmab=null
7998
}
8099

81100
@JsonCreator
@@ -87,8 +106,9 @@ public Experiment(@JsonProperty("id") String id,
87106
@JsonProperty("audienceConditions") Condition audienceConditions,
88107
@JsonProperty("variations") List<Variation> variations,
89108
@JsonProperty("forcedVariations") Map<String, String> userIdToVariationKeyMap,
90-
@JsonProperty("trafficAllocation") List<TrafficAllocation> trafficAllocation) {
91-
this(id, key, status, layerId, audienceIds, audienceConditions, variations, userIdToVariationKeyMap, trafficAllocation, "");
109+
@JsonProperty("trafficAllocation") List<TrafficAllocation> trafficAllocation,
110+
@JsonProperty("cmab") Cmab cmab) {
111+
this(id, key, status, layerId, audienceIds, audienceConditions, variations, userIdToVariationKeyMap, trafficAllocation, "", cmab);
92112
}
93113

94114
public Experiment(@Nonnull String id,
@@ -100,7 +120,8 @@ public Experiment(@Nonnull String id,
100120
@Nonnull List<Variation> variations,
101121
@Nonnull Map<String, String> userIdToVariationKeyMap,
102122
@Nonnull List<TrafficAllocation> trafficAllocation,
103-
@Nonnull String groupId) {
123+
@Nonnull String groupId,
124+
@Nullable Cmab cmab) {
104125
this.id = id;
105126
this.key = key;
106127
this.status = status == null ? ExperimentStatus.NOT_STARTED.toString() : status;
@@ -113,6 +134,7 @@ public Experiment(@Nonnull String id,
113134
this.userIdToVariationKeyMap = userIdToVariationKeyMap;
114135
this.variationKeyToVariationMap = ProjectConfigUtils.generateNameMapping(variations);
115136
this.variationIdToVariationMap = ProjectConfigUtils.generateIdMapping(variations);
137+
this.cmab = cmab;
116138
}
117139

118140
public String getId() {
@@ -163,6 +185,10 @@ public String getGroupId() {
163185
return groupId;
164186
}
165187

188+
public Cmab getCmab() {
189+
return cmab;
190+
}
191+
166192
public boolean isActive() {
167193
return status.equals(ExperimentStatus.RUNNING.toString()) ||
168194
status.equals(ExperimentStatus.LAUNCHED.toString());
@@ -281,6 +307,7 @@ public String toString() {
281307
", variationKeyToVariationMap=" + variationKeyToVariationMap +
282308
", userIdToVariationKeyMap=" + userIdToVariationKeyMap +
283309
", trafficAllocation=" + trafficAllocation +
310+
", cmab=" + cmab +
284311
'}';
285312
}
286313
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ public Group(@JsonProperty("id") String id,
6262
experiment.getVariations(),
6363
experiment.getUserIdToVariationKeyMap(),
6464
experiment.getTrafficAllocation(),
65-
id
65+
id,
66+
experiment.getCmab()
6667
);
6768
}
6869
this.experiments.add(experiment);

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

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,8 @@
2424
import com.google.gson.JsonParseException;
2525
import com.google.gson.reflect.TypeToken;
2626
import com.optimizely.ab.bucketing.DecisionService;
27-
import com.optimizely.ab.config.Experiment;
27+
import com.optimizely.ab.config.*;
2828
import com.optimizely.ab.config.Experiment.ExperimentStatus;
29-
import com.optimizely.ab.config.FeatureFlag;
30-
import com.optimizely.ab.config.FeatureVariable;
31-
import com.optimizely.ab.config.FeatureVariableUsageInstance;
32-
import com.optimizely.ab.config.TrafficAllocation;
33-
import com.optimizely.ab.config.Variation;
3429
import com.optimizely.ab.config.audience.AudienceIdCondition;
3530
import com.optimizely.ab.config.audience.Condition;
3631
import com.optimizely.ab.internal.ConditionUtils;
@@ -118,6 +113,27 @@ static Condition parseAudienceConditions(JsonObject experimentJson) {
118113

119114
}
120115

116+
static Cmab parseCmab(JsonObject cmabJson, JsonDeserializationContext context) {
117+
if (cmabJson == null) {
118+
return null;
119+
}
120+
121+
JsonArray attributeIdsJson = cmabJson.getAsJsonArray("attributeIds");
122+
List<String> attributeIds = new ArrayList<>();
123+
if (attributeIdsJson != null) {
124+
for (JsonElement attributeIdElement : attributeIdsJson) {
125+
attributeIds.add(attributeIdElement.getAsString());
126+
}
127+
}
128+
129+
int trafficAllocation = 0;
130+
if (cmabJson.has("trafficAllocation")) {
131+
trafficAllocation = cmabJson.get("trafficAllocation").getAsInt();
132+
}
133+
134+
return new Cmab(attributeIds, trafficAllocation);
135+
}
136+
121137
static Experiment parseExperiment(JsonObject experimentJson, String groupId, JsonDeserializationContext context) {
122138
String id = experimentJson.get("id").getAsString();
123139
String key = experimentJson.get("key").getAsString();
@@ -143,8 +159,16 @@ static Experiment parseExperiment(JsonObject experimentJson, String groupId, Jso
143159
List<TrafficAllocation> trafficAllocations =
144160
parseTrafficAllocation(experimentJson.getAsJsonArray("trafficAllocation"));
145161

162+
Cmab cmab = null;
163+
if (experimentJson.has("cmab")) {
164+
JsonObject cmabJson = experimentJson.getAsJsonObject("cmab");
165+
if (cmabJson != null) {
166+
cmab = parseCmab(cmabJson, context);
167+
}
168+
}
169+
146170
return new Experiment(id, key, status, layerId, audienceIds, conditions, variations, userIdToVariationKeyMap,
147-
trafficAllocations, groupId);
171+
trafficAllocations, groupId, cmab);
148172
}
149173

150174
static Experiment parseExperiment(JsonObject experimentJson, JsonDeserializationContext context) {

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,16 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
159159
List<TrafficAllocation> trafficAllocations =
160160
parseTrafficAllocation(experimentObject.getJSONArray("trafficAllocation"));
161161

162+
Cmab cmab = null;
163+
if (experimentObject.has("cmab")) {
164+
JSONObject cmabObject = experimentObject.optJSONObject("cmab");
165+
if (cmabObject != null) {
166+
cmab = parseCmab(cmabObject);
167+
}
168+
}
169+
162170
experiments.add(new Experiment(id, key, status, layerId, audienceIds, conditions, variations, userIdToVariationKeyMap,
163-
trafficAllocations, groupId));
171+
trafficAllocations, groupId, cmab));
164172
}
165173

166174
return experiments;
@@ -255,6 +263,23 @@ private List<TrafficAllocation> parseTrafficAllocation(JSONArray trafficAllocati
255263
return trafficAllocation;
256264
}
257265

266+
private Cmab parseCmab(JSONObject cmabObject) {
267+
if (cmabObject == null) {
268+
return null;
269+
}
270+
271+
JSONArray attributeIdsJson = cmabObject.optJSONArray("attributeIds");
272+
List<String> attributeIds = new ArrayList<String>();
273+
if (attributeIdsJson != null) {
274+
for (int i = 0; i < attributeIdsJson.length(); i++) {
275+
attributeIds.add(attributeIdsJson.getString(i));
276+
}
277+
}
278+
279+
int trafficAllocation = cmabObject.optInt("trafficAllocation", 0);
280+
return new Cmab(attributeIds, trafficAllocation);
281+
}
282+
258283
private List<Attribute> parseAttributes(JSONArray attributeJson) {
259284
List<Attribute> attributes = new ArrayList<Attribute>(attributeJson.length());
260285

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,17 @@ private List<Experiment> parseExperiments(JSONArray experimentJson, String group
166166
List<TrafficAllocation> trafficAllocations =
167167
parseTrafficAllocation((JSONArray) experimentObject.get("trafficAllocation"));
168168

169-
experiments.add(new Experiment(id, key, status, layerId, audienceIds, conditions, variations, userIdToVariationKeyMap,
170-
trafficAllocations, groupId));
169+
// Add cmab parsing
170+
Cmab cmab = null;
171+
if (experimentObject.containsKey("cmab")) {
172+
JSONObject cmabObject = (JSONObject) experimentObject.get("cmab");
173+
if (cmabObject != null) {
174+
cmab = parseCmab(cmabObject);
175+
}
176+
}
177+
178+
experiments.add(new Experiment(id, key, status, layerId, audienceIds, conditions, variations,
179+
userIdToVariationKeyMap, trafficAllocations, groupId, cmab));
171180
}
172181

173182
return experiments;
@@ -398,6 +407,26 @@ private List<Integration> parseIntegrations(JSONArray integrationsJson) {
398407
return integrations;
399408
}
400409

410+
private Cmab parseCmab(JSONObject cmabObject) {
411+
if (cmabObject == null) {
412+
return null;
413+
}
414+
415+
JSONArray attributeIdsJson = (JSONArray) cmabObject.get("attributeIds");
416+
List<String> attributeIds = new ArrayList<>();
417+
if (attributeIdsJson != null) {
418+
for (Object idObj : attributeIdsJson) {
419+
attributeIds.add((String) idObj);
420+
}
421+
}
422+
423+
Object trafficAllocationObj = cmabObject.get("trafficAllocation");
424+
int trafficAllocation = trafficAllocationObj != null ?
425+
((Long) trafficAllocationObj).intValue() : 0;
426+
427+
return new Cmab(attributeIds, trafficAllocation);
428+
}
429+
401430
@Override
402431
public String toJson(Object src) {
403432
return JSONValue.toJSONString(src);

0 commit comments

Comments
 (0)