Skip to content

Commit 32aea2c

Browse files
author
Vignesh Raja
authored
Release version 1.2.0 (#47)
1 parent 6a3f2aa commit 32aea2c

30 files changed

+681
-161
lines changed

.travis.yml

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,17 @@
11
language: java
22
jdk:
3+
- openjdk7
34
- oraclejdk7
5+
- oraclejdk8
46
install: true
5-
before_script:
6-
- git config user.name "Travis-CI"
7-
- git config user.email "noreply@travis-ci.org"
8-
- git checkout $TRAVIS_BRANCH
97
script:
108
- "./gradlew clean build check"
11-
# - '[ "${TRAVIS_PULL_REQUEST}" != "false" ] || ./gradlew release -Prelease.useAutomaticVersion=true'
12-
env:
13-
global:
14-
- TERM=dumb
15-
- secure: "JVJ1w5ImgQkBwplEjlyTq0UaJQZncQEa35ggIbCffTon/FnWauy+HL9rzjBR6vTtSRlPxbKKxOdR0fGZQg5hQU10TEadwNBF5nLlFKK+mAz32z0RjgWAJhiFqjvFYdfGPuPZpAUZLIe7UxtcpQZPF2cAkc4Zw/r1HTI0GKS5L/H8FwJWlR1txu9O6GWfT58ntrD18LzrHQ9M5PC3gc4U/Af7kiPjeXQf06zliy7PMaMw8m1XLicjwzEHW2cNVXB0WrZwgcSrblnidRxPJj05k5clULu5VsetqMkLHCxuPbnjR0+1sZ6IX/3yhH5u/dm/vVtWikCqfpH2bLQw0vcYqisBPaJ/RlOa4r7ROL+G8LRo94LqwEVmZ+fbEFCqigP+Wv9GlLKL+LKTPDYWEnrBcHsE4EOwpLviEZRixHf/HtKvMfuwLyzyIAVyKjU0MrFDsOvDRorC1HIyg66CwjkKg5LJwW4IOTNTOldOpiGhB4PR4bcMUU8wuB5ts7eGGYCShthS4kOtuHlSuxfv6qKGIz4z5nD8/JPxVUU+P3RtrvoGYoeIqd6SGC40cvYupCzULJIYwrCKrRTpimrSwdrEEtLp91WjyrrDfznlGzoDOdCS5XaActcn4lh+ztkpYD/Qj2j31955kOkxq0/9TP5qi9qNvJAeFwkhW3VSmJVRbLw="
16-
- secure: "3UGbdSed51Ul024Wj1l2zojolyMxCzlTERSJjXrh5mdcNAHxImZTNURUuKaQsJghnirjB3q124woWyymvepE8XdSH0Y7DYkqV247vczXm1nHhbUpzVQ8xsDWTE6AXIyq1CzGzKFK8Ws0C+xXOZoBr2l9dy6oF4rBxTYTBlL8BvqGtcZw3d3eWNI9wQ+l6XGbQDw3Ex2iJaUr9NOI1kD4Q0gcUSX+Zgowe1xlaySrRLXg5iZVUCLNbitJEJ91Xd3oCksqfKBBe2b24M6edhCLNOMQ4u0MTEu28D6gltqojqmp1UHI6fJD8+P79h6PfpMPA+3vB3kTQ9vwG/5L5JoTe5JJPp+yUgbEBH5QzI7si6oVTFHb8oTN2/TMJV+N4QjILrasfreAYUA2kHXzxmxlodNsILNvl5OgF0ValwOvgPDZfkGytMnvLWow6gw8gSYtiTYJjNSMXnpa9kjCLMUyizDFRn4PpcMi2bfml/vR/qlVMnln3AwSukPGqQ4uZhRnIkzBJQdXoxoYTaVOcfsgF8dFWwOShin/RTygwwg5cjm0Nhn6RmkFtt81arLeVho/SeqOjEkvcCV6a7bhhmCZpZvYZu57dLfF/jPHYmW30X3Pg9e+7VsQ61xQWnlVV1g8KjM0qVnThoUVj8j62bXIo/P5scaKkxg9j5/Mdq6t02E="
179
cache:
1810
gradle: true
1911
directories:
2012
- "$HOME/.gradle/caches"
2113
- "$HOME/.gradle/wrapper"
22-
after_script:
23-
- git tag travis-build-$TRAVIS_BUILD_NUMBER
24-
- git push --tags
2514
branches:
2615
only:
2716
- master
17+
- devel

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 1.2.0
2+
3+
- Change position of `activateExperiment` parameter in the method signatures of `getVariableString`, `getVariableBoolean`, `getVariableInteger`, and `getVariableFloat`
4+
- Change `UserExperimentRecord` to `UserProfile`
5+
- Add support for IP anonymization
6+
- Add `NotificationListener` for SDK events
7+
18
## 1.1.0
29

310
- Add support for live variables

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

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import com.optimizely.ab.annotations.VisibleForTesting;
2020
import com.optimizely.ab.bucketing.Bucketer;
21-
import com.optimizely.ab.bucketing.UserExperimentRecord;
21+
import com.optimizely.ab.bucketing.UserProfile;
2222
import com.optimizely.ab.config.Attribute;
2323
import com.optimizely.ab.config.EventType;
2424
import com.optimizely.ab.config.Experiment;
@@ -39,6 +39,8 @@
3939
import com.optimizely.ab.event.internal.EventBuilderV2;
4040
import com.optimizely.ab.event.internal.payload.Event.ClientEngine;
4141
import com.optimizely.ab.internal.ProjectValidationUtils;
42+
import com.optimizely.ab.notification.NotificationListener;
43+
import com.optimizely.ab.notification.NotificationBroadcaster;
4244

4345
import org.slf4j.Logger;
4446
import org.slf4j.LoggerFactory;
@@ -89,6 +91,7 @@ public class Optimizely {
8991
@VisibleForTesting final ProjectConfig projectConfig;
9092
@VisibleForTesting final EventHandler eventHandler;
9193
@VisibleForTesting final ErrorHandler errorHandler;
94+
@VisibleForTesting final NotificationBroadcaster notificationBroadcaster = new NotificationBroadcaster();
9295

9396
private Optimizely(@Nonnull ProjectConfig projectConfig,
9497
@Nonnull Bucketer bucketer,
@@ -104,7 +107,7 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,
104107

105108
// Do work here that should be done once per Optimizely lifecycle
106109
@VisibleForTesting void initialize() {
107-
bucketer.cleanUserExperimentRecords();
110+
bucketer.cleanUserProfiles();
108111
}
109112

110113
//======== activate calls ========//
@@ -180,6 +183,8 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,
180183
logger.error("Unexpected exception in event dispatcher", e);
181184
}
182185

186+
notificationBroadcaster.broadcastExperimentActivated(experiment, userId, attributes, variation);
187+
183188
return variation;
184189
}
185190

@@ -258,15 +263,15 @@ private void track(@Nonnull String eventName,
258263
//======== live variable getters ========//
259264

260265
public @Nullable String getVariableString(@Nonnull String variableKey,
261-
boolean activateExperiment,
262-
@Nonnull String userId) throws UnknownLiveVariableException {
263-
return getVariableString(variableKey, activateExperiment, userId, Collections.<String, String>emptyMap());
266+
@Nonnull String userId,
267+
boolean activateExperiment) throws UnknownLiveVariableException {
268+
return getVariableString(variableKey, userId, Collections.<String, String>emptyMap(), activateExperiment);
264269
}
265270

266271
public @Nullable String getVariableString(@Nonnull String variableKey,
267-
boolean activateExperiment,
268272
@Nonnull String userId,
269-
@Nonnull Map<String, String> attributes)
273+
@Nonnull Map<String, String> attributes,
274+
boolean activateExperiment)
270275
throws UnknownLiveVariableException {
271276

272277
LiveVariable variable = getLiveVariableOrThrow(projectConfig, variableKey);
@@ -303,18 +308,18 @@ private void track(@Nonnull String eventName,
303308
}
304309

305310
public @Nullable Boolean getVariableBoolean(@Nonnull String variableKey,
306-
boolean activateExperiment,
307-
@Nonnull String userId) throws UnknownLiveVariableException {
308-
return getVariableBoolean(variableKey, activateExperiment, userId, Collections.<String, String>emptyMap());
311+
@Nonnull String userId,
312+
boolean activateExperiment) throws UnknownLiveVariableException {
313+
return getVariableBoolean(variableKey, userId, Collections.<String, String>emptyMap(), activateExperiment);
309314
}
310315

311316
public @Nullable Boolean getVariableBoolean(@Nonnull String variableKey,
312-
boolean activateExperiment,
313317
@Nonnull String userId,
314-
@Nonnull Map<String, String> attributes)
318+
@Nonnull Map<String, String> attributes,
319+
boolean activateExperiment)
315320
throws UnknownLiveVariableException {
316321

317-
String variableValueString = getVariableString(variableKey, activateExperiment, userId, attributes);
322+
String variableValueString = getVariableString(variableKey, userId, attributes, activateExperiment);
318323
if (variableValueString != null) {
319324
return Boolean.parseBoolean(variableValueString);
320325
}
@@ -323,18 +328,18 @@ private void track(@Nonnull String eventName,
323328
}
324329

325330
public @Nullable Integer getVariableInteger(@Nonnull String variableKey,
326-
boolean activateExperiment,
327-
@Nonnull String userId) throws UnknownLiveVariableException {
328-
return getVariableInteger(variableKey, activateExperiment, userId, Collections.<String, String>emptyMap());
331+
@Nonnull String userId,
332+
boolean activateExperiment) throws UnknownLiveVariableException {
333+
return getVariableInteger(variableKey, userId, Collections.<String, String>emptyMap(), activateExperiment);
329334
}
330335

331336
public @Nullable Integer getVariableInteger(@Nonnull String variableKey,
332-
boolean activateExperiment,
333337
@Nonnull String userId,
334-
@Nonnull Map<String, String> attributes)
338+
@Nonnull Map<String, String> attributes,
339+
boolean activateExperiment)
335340
throws UnknownLiveVariableException {
336341

337-
String variableValueString = getVariableString(variableKey, activateExperiment, userId, attributes);
342+
String variableValueString = getVariableString(variableKey, userId, attributes, activateExperiment);
338343
if (variableValueString != null) {
339344
try {
340345
return Integer.parseInt(variableValueString);
@@ -348,18 +353,18 @@ private void track(@Nonnull String eventName,
348353
}
349354

350355
public @Nullable Float getVariableFloat(@Nonnull String variableKey,
351-
boolean activateExperiment,
352-
@Nonnull String userId) throws UnknownLiveVariableException {
353-
return getVariableFloat(variableKey, activateExperiment, userId, Collections.<String, String>emptyMap());
356+
@Nonnull String userId,
357+
boolean activateExperiment) throws UnknownLiveVariableException {
358+
return getVariableFloat(variableKey, userId, Collections.<String, String>emptyMap(), activateExperiment);
354359
}
355360

356361
public @Nullable Float getVariableFloat(@Nonnull String variableKey,
357-
boolean activateExperiment,
358362
@Nonnull String userId,
359-
@Nonnull Map<String, String> attributes)
363+
@Nonnull Map<String, String> attributes,
364+
boolean activateExperiment)
360365
throws UnknownLiveVariableException {
361366

362-
String variableValueString = getVariableString(variableKey, activateExperiment, userId, attributes);
367+
String variableValueString = getVariableString(variableKey, userId, attributes, activateExperiment);
363368
if (variableValueString != null) {
364369
try {
365370
return Float.parseFloat(variableValueString);
@@ -438,6 +443,33 @@ private static ProjectConfig getProjectConfig(String datafile) throws ConfigPars
438443
return DefaultConfigParser.getInstance().parseProjectConfig(datafile);
439444
}
440445

446+
//======== Notification listeners ========//
447+
448+
/**
449+
* Add a {@link NotificationListener} if it does not exist already.
450+
*
451+
* @param listener listener to add
452+
*/
453+
public void addNotificationListener(@Nonnull NotificationListener listener) {
454+
notificationBroadcaster.addListener(listener);
455+
}
456+
457+
/**
458+
* Remove a {@link NotificationListener} if it exists.
459+
*
460+
* @param listener listener to remove
461+
*/
462+
public void removeNotificationListener(@Nonnull NotificationListener listener) {
463+
notificationBroadcaster.removeListener(listener);
464+
}
465+
466+
/**
467+
* Remove all {@link NotificationListener}.
468+
*/
469+
public void clearNotificationListeners() {
470+
notificationBroadcaster.clearListeners();
471+
}
472+
441473
//======== Helper methods ========//
442474

443475
/**
@@ -596,7 +628,7 @@ public static class Builder {
596628

597629
private String datafile;
598630
private Bucketer bucketer;
599-
private UserExperimentRecord userExperimentRecord;
631+
private UserProfile userProfile;
600632
private ErrorHandler errorHandler;
601633
private EventHandler eventHandler;
602634
private EventBuilder eventBuilder;
@@ -615,8 +647,8 @@ public Builder withErrorHandler(ErrorHandler errorHandler) {
615647
return this;
616648
}
617649

618-
public Builder withUserExperimentRecord(UserExperimentRecord userExperimentRecord) {
619-
this.userExperimentRecord = userExperimentRecord;
650+
public Builder withUserProfile(UserProfile userProfile) {
651+
this.userProfile = userProfile;
620652
return this;
621653
}
622654

@@ -653,7 +685,7 @@ public Optimizely build() throws ConfigParseException {
653685

654686
// use the default bucketer and event builder, if no overrides were provided
655687
if (bucketer == null) {
656-
bucketer = new Bucketer(projectConfig, userExperimentRecord);
688+
bucketer = new Bucketer(projectConfig, userProfile);
657689
}
658690

659691
if (clientEngine == null) {

core-api/src/main/java/com/optimizely/ab/bucketing/Bucketer.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public class Bucketer {
4747

4848
private final ProjectConfig projectConfig;
4949

50-
@Nullable private final UserExperimentRecord userExperimentRecord;
50+
@Nullable private final UserProfile userProfile;
5151

5252
private static final Logger logger = LoggerFactory.getLogger(Bucketer.class);
5353

@@ -63,9 +63,9 @@ public Bucketer(ProjectConfig projectConfig) {
6363
this(projectConfig, null);
6464
}
6565

66-
public Bucketer(ProjectConfig projectConfig, @Nullable UserExperimentRecord userExperimentRecord) {
66+
public Bucketer(ProjectConfig projectConfig, @Nullable UserProfile userProfile) {
6767
this.projectConfig = projectConfig;
68-
this.userExperimentRecord = userExperimentRecord;
68+
this.userProfile = userProfile;
6969
}
7070

7171
private String bucketToEntity(int bucketValue, List<TrafficAllocation> trafficAllocations) {
@@ -112,12 +112,12 @@ private Variation bucketToVariation(@Nonnull Experiment experiment,
112112
String experimentKey = experiment.getKey();
113113
String combinedBucketId = userId + experimentId;
114114

115-
// If a user experiment record instance is present then check it for a saved variation
116-
if (userExperimentRecord != null) {
117-
String variationKey = userExperimentRecord.lookup(userId, experimentKey);
115+
// If a user profile instance is present then check it for a saved variation
116+
if (userProfile != null) {
117+
String variationKey = userProfile.lookup(userId, experimentKey);
118118
if (variationKey != null) {
119119
logger.info("Returning previously activated variation \"{}\" of experiment \"{}\" "
120-
+ "for user \"{}\" from user experiment record.",
120+
+ "for user \"{}\" from user profile.",
121121
variationKey, experimentKey, userId);
122122
// A variation is stored for this combined bucket id
123123
return projectConfig
@@ -127,7 +127,7 @@ private Variation bucketToVariation(@Nonnull Experiment experiment,
127127
.get(variationKey);
128128
} else {
129129
logger.info("No previously activated variation of experiment \"{}\" "
130-
+ "for user \"{}\" found in user experiment record.",
130+
+ "for user \"{}\" found in user profile.",
131131
experimentKey, userId);
132132
}
133133
}
@@ -145,9 +145,9 @@ private Variation bucketToVariation(@Nonnull Experiment experiment,
145145
logger.info("User \"{}\" is in variation \"{}\" of experiment \"{}\".", userId, variationKey,
146146
experimentKey);
147147

148-
// If a user experiment record is present give it a variation to store
149-
if (userExperimentRecord != null) {
150-
boolean saved = userExperimentRecord.save(userId, experiment.getKey(), variationKey);
148+
// If a user profile is present give it a variation to store
149+
if (userProfile != null) {
150+
boolean saved = userProfile.save(userId, experiment.getKey(), variationKey);
151151
if (saved) {
152152
logger.info("Saved variation \"{}\" of experiment \"{}\" for user \"{}\".",
153153
variationKey, experimentKey, userId);
@@ -224,23 +224,23 @@ int generateBucketValue(int hashCode) {
224224
}
225225

226226
@Nullable
227-
public UserExperimentRecord getUserExperimentRecord() {
228-
return userExperimentRecord;
227+
public UserProfile getUserProfile() {
228+
return userProfile;
229229
}
230230

231231
/**
232-
* Gives implementations of {@link UserExperimentRecord} a chance to remove records
232+
* Gives implementations of {@link UserProfile} a chance to remove records
233233
* of experiments that are deleted or not running.
234234
*/
235-
public void cleanUserExperimentRecords() {
236-
if (userExperimentRecord != null) {
237-
Map<String, Map<String,String>> records = userExperimentRecord.getAllRecords();
235+
public void cleanUserProfiles() {
236+
if (userProfile != null) {
237+
Map<String, Map<String,String>> records = userProfile.getAllRecords();
238238
if (records != null) {
239239
for (Map.Entry<String,Map<String,String>> record : records.entrySet()) {
240240
for (String experimentKey : record.getValue().keySet()) {
241241
Experiment experiment = projectConfig.getExperimentKeyMapping().get(experimentKey);
242242
if (experiment == null || !experiment.isRunning()) {
243-
userExperimentRecord.remove(record.getKey(), experimentKey);
243+
userProfile.remove(record.getKey(), experimentKey);
244244
}
245245
}
246246
}

core-api/src/main/java/com/optimizely/ab/bucketing/UserExperimentRecord.java renamed to core-api/src/main/java/com/optimizely/ab/bucketing/UserProfile.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
* user experience after changing traffic allocations. Also, this interface gives users
2626
* a hook to keep track of activation history.
2727
*/
28-
public interface UserExperimentRecord {
28+
public interface UserProfile {
2929

3030
/**
3131
* Called when implementors should save an activation
@@ -47,7 +47,7 @@ public interface UserExperimentRecord {
4747
String lookup(String userId, String experimentKey);
4848

4949
/**
50-
* Called when user experiment record should be removed
50+
* Called when user profile should be removed
5151
*
5252
* Records should be removed when an experiment is not running or when an experiment has been
5353
* deleted.

0 commit comments

Comments
 (0)