Skip to content

Commit ad048df

Browse files
Merge branch 'master' into farhan-anjum/FSSDK-11134-cmab-datafile-parsing
2 parents 2640eaa + 962ca8f commit ad048df

Some content is hidden

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

41 files changed

+2872
-204
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ jobs:
2222
run_build:
2323
runs-on: ubuntu-latest
2424
steps:
25-
- uses: actions/checkout@v2
25+
- uses: actions/checkout@v4
2626
- name: set up JDK 8
2727
uses: actions/setup-java@v2
2828
with:
2929
java-version: '8'
3030
distribution: 'temurin'
31-
cache: gradle
3231
- name: Grant execute permission for gradlew
3332
run: chmod +x gradlew
3433
- name: ${{ inputs.action }}

.github/workflows/integration_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
test:
1414
runs-on: ubuntu-latest
1515
steps:
16-
- uses: actions/checkout@v3
16+
- uses: actions/checkout@v4
1717
with:
1818
# You should create a personal access token and store it in your repository
1919
token: ${{ secrets.CI_USER_TOKEN }}

.github/workflows/java.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ jobs:
8383
- name: Check on failures
8484
if: always() && steps.unit_tests.outcome != 'success'
8585
run: |
86-
cat /home/runner/java-sdk/core-api/build/reports/findbugs/main.html
87-
cat /home/runner/java-sdk/core-api/build/reports/findbugs/test.html
86+
cat /Users/runner/work/java-sdk/core-api/build/reports/spotbugs/main.html
87+
cat /Users/runner/work/java-sdk/core-api/build/reports/spotbugs/test.html
8888
- name: Check on success
8989
if: always() && steps.unit_tests.outcome == 'success'
9090
run: |

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ classes
2525
.vagrant
2626
.DS_Store
2727
.venv
28+
29+
.vscode/mcp.json

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Optimizely Java X SDK Changelog
22

3+
## [4.2.2]
4+
May 28th, 2025
5+
6+
### Fixes
7+
- Added experimentId and variationId to decision notification ([#569](https://github.com/optimizely/java-sdk/pull/569)).
8+
39
## [4.2.1]
410
Feb 19th, 2025
511

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ You can run all unit tests with:
7070

7171
### Checking for bugs
7272

73-
We utilize [FindBugs](http://findbugs.sourceforge.net/) to identify possible bugs in the SDK. To run the check:
73+
We utilize [SpotBugs](https://spotbugs.github.io/) to identify possible bugs in the SDK. To run the check:
7474

7575
```
7676

build.gradle

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ plugins {
22
id 'com.github.kt3k.coveralls' version '2.12.2'
33
id 'jacoco'
44
id 'me.champeau.gradle.jmh' version '0.5.3'
5-
id 'nebula.optional-base' version '3.2.0'
5+
id 'nebula.optional-base' version '3.1.0'
66
id 'com.github.hierynomus.license' version '0.16.1'
7-
id 'com.github.spotbugs' version "4.5.0"
7+
id 'com.github.spotbugs' version "6.0.14"
88
id 'maven-publish'
99
}
1010

@@ -73,6 +73,7 @@ configure(publishedProjects) {
7373

7474
spotbugs {
7575
spotbugsJmh.enabled = false
76+
reportLevel = com.github.spotbugs.snom.Confidence.valueOf('HIGH')
7677
}
7778

7879
test {
@@ -115,6 +116,7 @@ configure(publishedProjects) {
115116
configurations.all {
116117
resolutionStrategy {
117118
force "junit:junit:${junitVersion}"
119+
force 'com.netflix.nebula:nebula-gradle-interop:2.2.2'
118120
}
119121
}
120122

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,8 @@ private OptimizelyDecision createOptimizelyDecision(
13031303
ProjectConfig projectConfig
13041304
) {
13051305
String userId = user.getUserId();
1306+
String experimentId = null;
1307+
String variationId = null;
13061308

13071309
Boolean flagEnabled = false;
13081310
if (flagDecision.variation != null) {
@@ -1336,6 +1338,8 @@ private OptimizelyDecision createOptimizelyDecision(
13361338

13371339

13381340
Boolean decisionEventDispatched = false;
1341+
experimentId = flagDecision.experiment != null ? flagDecision.experiment.getId() : null;
1342+
variationId = flagDecision.variation != null ? flagDecision.variation.getId() : null;
13391343

13401344
Map<String, Object> attributes = user.getAttributes();
13411345
Map<String, ?> copiedAttributes = new HashMap<>(attributes);
@@ -1362,6 +1366,8 @@ private OptimizelyDecision createOptimizelyDecision(
13621366
.withRuleKey(ruleKey)
13631367
.withReasons(reasonsToReport)
13641368
.withDecisionEventDispatched(decisionEventDispatched)
1369+
.withExperimentId(experimentId)
1370+
.withVariationId(variationId)
13651371
.build();
13661372
notificationCenter.send(decisionNotification);
13671373

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public class DatafileProjectConfig implements ProjectConfig {
6363
private final boolean anonymizeIP;
6464
private final boolean sendFlagDecisions;
6565
private final Boolean botFiltering;
66+
private final String region;
6667
private final String hostForODP;
6768
private final String publicKeyForODP;
6869
private final List<Attribute> attributes;
@@ -95,6 +96,8 @@ public class DatafileProjectConfig implements ProjectConfig {
9596
// other mappings
9697
private final Map<String, Experiment> variationIdToExperimentMapping;
9798

99+
private final HoldoutConfig holdoutConfig;
100+
98101
private String datafile;
99102

100103
// v2 constructor
@@ -113,6 +116,7 @@ public DatafileProjectConfig(String accountId, String projectId, String version,
113116
anonymizeIP,
114117
false,
115118
null,
119+
null,
116120
projectId,
117121
revision,
118122
null,
@@ -124,6 +128,7 @@ public DatafileProjectConfig(String accountId, String projectId, String version,
124128
eventType,
125129
experiments,
126130
null,
131+
null,
127132
groups,
128133
null,
129134
null
@@ -135,6 +140,7 @@ public DatafileProjectConfig(String accountId,
135140
boolean anonymizeIP,
136141
boolean sendFlagDecisions,
137142
Boolean botFiltering,
143+
String region,
138144
String projectId,
139145
String revision,
140146
String sdkKey,
@@ -145,6 +151,7 @@ public DatafileProjectConfig(String accountId,
145151
List<Audience> typedAudiences,
146152
List<EventType> events,
147153
List<Experiment> experiments,
154+
List<Holdout> holdouts,
148155
List<FeatureFlag> featureFlags,
149156
List<Group> groups,
150157
List<Rollout> rollouts,
@@ -158,6 +165,7 @@ public DatafileProjectConfig(String accountId,
158165
this.anonymizeIP = anonymizeIP;
159166
this.sendFlagDecisions = sendFlagDecisions;
160167
this.botFiltering = botFiltering;
168+
this.region = region != null ? region : "US";
161169

162170
this.attributes = Collections.unmodifiableList(attributes);
163171
this.audiences = Collections.unmodifiableList(audiences);
@@ -187,6 +195,12 @@ public DatafileProjectConfig(String accountId,
187195
allExperiments.addAll(aggregateGroupExperiments(groups));
188196
this.experiments = Collections.unmodifiableList(allExperiments);
189197

198+
if (holdouts == null) {
199+
this.holdoutConfig = new HoldoutConfig();
200+
} else {
201+
this.holdoutConfig = new HoldoutConfig(holdouts);
202+
}
203+
190204
String publicKeyForODP = "";
191205
String hostForODP = "";
192206
if (integrations == null) {
@@ -424,6 +438,11 @@ public Boolean getBotFiltering() {
424438
return botFiltering;
425439
}
426440

441+
@Override
442+
public String getRegion() {
443+
return region;
444+
}
445+
427446
@Override
428447
public List<Group> getGroups() {
429448
return groups;
@@ -434,6 +453,21 @@ public List<Experiment> getExperiments() {
434453
return experiments;
435454
}
436455

456+
@Override
457+
public List<Holdout> getHoldouts() {
458+
return holdoutConfig.getAllHoldouts();
459+
}
460+
461+
@Override
462+
public List<Holdout> getHoldoutForFlag(@Nonnull String id) {
463+
return holdoutConfig.getHoldoutForFlag(id);
464+
}
465+
466+
@Override
467+
public Holdout getHoldout(@Nonnull String id) {
468+
return holdoutConfig.getHoldout(id);
469+
}
470+
437471
@Override
438472
public Set<String> getAllSegments() {
439473
return this.allSegments;
@@ -587,6 +621,7 @@ public String toString() {
587621
", version='" + version + '\'' +
588622
", anonymizeIP=" + anonymizeIP +
589623
", botFiltering=" + botFiltering +
624+
", region=" + region +
590625
", attributes=" + attributes +
591626
", audiences=" + audiences +
592627
", typedAudiences=" + typedAudiences +

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

Lines changed: 1 addition & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
*/
3535
@Immutable
3636
@JsonIgnoreProperties(ignoreUnknown = true)
37-
public class Experiment implements IdKeyMapped {
37+
public class Experiment implements ExperimentCore {
3838

3939
private final String id;
4040
private final String key;
@@ -43,10 +43,6 @@ public class Experiment implements IdKeyMapped {
4343
private final String groupId;
4444
private final Cmab cmab;
4545

46-
private final String AND = "AND";
47-
private final String OR = "OR";
48-
private final String NOT = "NOT";
49-
5046
private final List<String> audienceIds;
5147
private final Condition<AudienceIdCondition> audienceConditions;
5248
private final List<Variation> variations;
@@ -202,98 +198,6 @@ public boolean isLaunched() {
202198
return status.equals(ExperimentStatus.LAUNCHED.toString());
203199
}
204200

205-
public String serializeConditions(Map<String, String> audiencesMap) {
206-
Condition condition = this.audienceConditions;
207-
return condition instanceof EmptyCondition ? "" : this.serialize(condition, audiencesMap);
208-
}
209-
210-
private String getNameFromAudienceId(String audienceId, Map<String, String> audiencesMap) {
211-
StringBuilder audienceName = new StringBuilder();
212-
if (audiencesMap != null && audiencesMap.get(audienceId) != null) {
213-
audienceName.append("\"" + audiencesMap.get(audienceId) + "\"");
214-
} else {
215-
audienceName.append("\"" + audienceId + "\"");
216-
}
217-
return audienceName.toString();
218-
}
219-
220-
private String getOperandOrAudienceId(Condition condition, Map<String, String> audiencesMap) {
221-
if (condition != null) {
222-
if (condition instanceof AudienceIdCondition) {
223-
return this.getNameFromAudienceId(condition.getOperandOrId(), audiencesMap);
224-
} else {
225-
return condition.getOperandOrId();
226-
}
227-
} else {
228-
return "";
229-
}
230-
}
231-
232-
public String serialize(Condition condition, Map<String, String> audiencesMap) {
233-
StringBuilder stringBuilder = new StringBuilder();
234-
List<Condition> conditions;
235-
236-
String operand = this.getOperandOrAudienceId(condition, audiencesMap);
237-
switch (operand){
238-
case (AND):
239-
conditions = ((AndCondition<?>) condition).getConditions();
240-
stringBuilder.append(this.getNameOrNextCondition(operand, conditions, audiencesMap));
241-
break;
242-
case (OR):
243-
conditions = ((OrCondition<?>) condition).getConditions();
244-
stringBuilder.append(this.getNameOrNextCondition(operand, conditions, audiencesMap));
245-
break;
246-
case (NOT):
247-
stringBuilder.append(operand + " ");
248-
Condition notCondition = ((NotCondition<?>) condition).getCondition();
249-
if (notCondition instanceof AudienceIdCondition) {
250-
stringBuilder.append(serialize(notCondition, audiencesMap));
251-
} else {
252-
stringBuilder.append("(" + serialize(notCondition, audiencesMap) + ")");
253-
}
254-
break;
255-
default:
256-
stringBuilder.append(operand);
257-
break;
258-
}
259-
260-
return stringBuilder.toString();
261-
}
262-
263-
public String getNameOrNextCondition(String operand, List<Condition> conditions, Map<String, String> audiencesMap) {
264-
StringBuilder stringBuilder = new StringBuilder();
265-
int index = 0;
266-
if (conditions.isEmpty()) {
267-
return "";
268-
} else if (conditions.size() == 1) {
269-
return serialize(conditions.get(0), audiencesMap);
270-
} else {
271-
for (Condition con : conditions) {
272-
index++;
273-
if (index + 1 <= conditions.size()) {
274-
if (con instanceof AudienceIdCondition) {
275-
String audienceName = this.getNameFromAudienceId(((AudienceIdCondition<?>) con).getAudienceId(),
276-
audiencesMap);
277-
stringBuilder.append( audienceName + " ");
278-
} else {
279-
stringBuilder.append("(" + serialize(con, audiencesMap) + ") ");
280-
}
281-
stringBuilder.append(operand);
282-
stringBuilder.append(" ");
283-
} else {
284-
if (con instanceof AudienceIdCondition) {
285-
String audienceName = this.getNameFromAudienceId(((AudienceIdCondition<?>) con).getAudienceId(),
286-
audiencesMap);
287-
stringBuilder.append(audienceName);
288-
} else {
289-
stringBuilder.append("(" + serialize(con, audiencesMap) + ")");
290-
}
291-
}
292-
}
293-
}
294-
return stringBuilder.toString();
295-
}
296-
297201
@Override
298202
public String toString() {
299203
return "Experiment{" +

0 commit comments

Comments
 (0)