diff --git a/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java b/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java index 77e1d086c..e4ac6c294 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java +++ b/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java @@ -58,6 +58,7 @@ public String toString() { private final String projectId; private final String revision; private final String version; + private final boolean anonymizeIP; private final List groups; private final List experiments; private final List attributes; @@ -79,18 +80,19 @@ public String toString() { public ProjectConfig(String accountId, String projectId, String version, String revision, List groups, List experiments, List attributes, List eventType, List audiences) { - this(accountId, projectId, version, revision, groups, experiments, attributes, eventType, audiences, + this(accountId, projectId, version, revision, groups, experiments, attributes, eventType, audiences, false, null); } public ProjectConfig(String accountId, String projectId, String version, String revision, List groups, List experiments, List attributes, List eventType, - List audiences, List liveVariables) { + List audiences, boolean anonymizeIP, List liveVariables) { this.accountId = accountId; this.projectId = projectId; this.version = version; this.revision = revision; + this.anonymizeIP = anonymizeIP; this.groups = Collections.unmodifiableList(groups); List allExperiments = new ArrayList(); @@ -151,6 +153,10 @@ public String getRevision() { return revision; } + public boolean getAnonymizeIP() { + return anonymizeIP; + } + public List getGroups() { return groups; } @@ -233,6 +239,7 @@ public String toString() { ", projectId='" + projectId + '\'' + ", revision='" + revision + '\'' + ", version='" + version + '\'' + + ", anonymizeIP='" + anonymizeIP + '\'' + ", groups=" + groups + ", experiments=" + experiments + ", attributes=" + attributes + diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java index 538ac92ac..b12b0da45 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java @@ -73,13 +73,16 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse List audiences = parseAudiences(rootObject.getJSONArray("audiences")); List groups = parseGroups(rootObject.getJSONArray("groups")); + boolean anonymizeIP = false; List liveVariables = null; if (version.equals(ProjectConfig.Version.V3.toString())) { liveVariables = parseLiveVariables(rootObject.getJSONArray("variables")); + + anonymizeIP = rootObject.getBoolean("anonymizeIP"); } return new ProjectConfig(accountId, projectId, version, revision, groups, experiments, attributes, events, - audiences, liveVariables); + audiences, anonymizeIP, liveVariables); } catch (Exception e) { throw new ConfigParseException("Unable to parse datafile: " + json, e); } diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java index 551a08e6b..e3ba0236c 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java @@ -75,13 +75,16 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse List audiences = parseAudiences((JSONArray)parser.parse(rootObject.get("audiences").toString())); List groups = parseGroups((JSONArray)rootObject.get("groups")); + boolean anonymizeIP = false; List liveVariables = null; if (version.equals(ProjectConfig.Version.V3.toString())) { liveVariables = parseLiveVariables((JSONArray)rootObject.get("variables")); + + anonymizeIP = (Boolean)rootObject.get("anonymizeIP"); } return new ProjectConfig(accountId, projectId, version, revision, groups, experiments, attributes, events, - audiences, liveVariables); + audiences, anonymizeIP, liveVariables); } catch (Exception e) { throw new ConfigParseException("Unable to parse datafile: " + json, e); } diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java index c552fa48d..283a96119 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java @@ -72,14 +72,17 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa List audiences = context.deserialize(jsonObject.get("audiences").getAsJsonArray(), audienceType); + boolean anonymizeIP = false; // live variables should be null if using V1 List liveVariables = null; if (version.equals(ProjectConfig.Version.V3.toString())) { Type liveVariablesType = new TypeToken>() {}.getType(); liveVariables = context.deserialize(jsonObject.getAsJsonArray("variables"), liveVariablesType); + + anonymizeIP = jsonObject.get("anonymizeIP").getAsBoolean(); } return new ProjectConfig(accountId, projectId, version, revision, groups, experiments, attributes, events, - audiences, liveVariables); + audiences, anonymizeIP, liveVariables); } } diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java index e2aded68f..ddc3675d1 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java @@ -68,13 +68,15 @@ public ProjectConfig deserialize(JsonParser parser, DeserializationContext conte List audiences = mapper.readValue(node.get("audiences").toString(), new TypeReference>() {}); + boolean anonymizeIP = false; List liveVariables = null; if (version.equals(ProjectConfig.Version.V3.toString())) { liveVariables = mapper.readValue(node.get("variables").toString(), new TypeReference>() {}); + anonymizeIP = node.get("anonymizeIP").asBoolean(); } return new ProjectConfig(accountId, projectId, version, revision, groups, experiments, attributes, events, - audiences, liveVariables); + audiences, anonymizeIP, liveVariables); } } \ No newline at end of file diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilderV2.java b/core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilderV2.java index 7a3478df4..329e2d74f 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilderV2.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilderV2.java @@ -51,8 +51,8 @@ public class EventBuilderV2 extends EventBuilder { private static final Logger logger = LoggerFactory.getLogger(EventBuilderV2.class); - static final String IMPRESSION_ENDPOINT = "https://p13nlog.dz.optimizely.com/log/decision"; - static final String CONVERSION_ENDPOINT = "https://p13nlog.dz.optimizely.com/log/event"; + static final String IMPRESSION_ENDPOINT = "https://logx.optimizely.com/log/decision"; + static final String CONVERSION_ENDPOINT = "https://logx.optimizely.com/log/event"; @VisibleForTesting public final ClientEngine clientEngine; @@ -95,6 +95,7 @@ public LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig, impressionPayload.setUserFeatures(createFeatures(attributes, projectConfig)); impressionPayload.setClientEngine(clientEngine); impressionPayload.setClientVersion(clientVersion); + impressionPayload.setAnonymizeIP(projectConfig.getAnonymizeIP()); String payload = this.serializer.serialize(impressionPayload); return new LogEvent(RequestMethod.POST, IMPRESSION_ENDPOINT, Collections.emptyMap(), payload); @@ -133,6 +134,7 @@ public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig, conversionPayload.setEventFeatures(Collections.emptyList()); conversionPayload.setIsGlobalHoldback(false); + conversionPayload.setAnonymizeIP(projectConfig.getAnonymizeIP()); conversionPayload.setClientEngine(clientEngine); conversionPayload.setClientVersion(clientVersion); diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Conversion.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Conversion.java index 187eed879..bf30d25c7 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Conversion.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Conversion.java @@ -31,12 +31,13 @@ public class Conversion extends Event { private List eventMetrics; private List eventFeatures; private boolean isGlobalHoldback; + private boolean anonymizeIP; public Conversion() { } public Conversion(String visitorId, long timestamp, String projectId, String accountId, List userFeatures, List layerStates, String eventEntityId, String eventName, - List eventMetrics, List eventFeatures, boolean isGlobalHoldback) { + List eventMetrics, List eventFeatures, boolean isGlobalHoldback, boolean anonymizeIP) { this.visitorId = visitorId; this.timestamp = timestamp; this.projectId = projectId; @@ -48,6 +49,7 @@ public Conversion(String visitorId, long timestamp, String projectId, String acc this.eventMetrics = eventMetrics; this.eventFeatures = eventFeatures; this.isGlobalHoldback = isGlobalHoldback; + this.anonymizeIP = anonymizeIP; } public String getVisitorId() { @@ -138,6 +140,10 @@ public void setIsGlobalHoldback(boolean globalHoldback) { this.isGlobalHoldback = globalHoldback; } + public boolean getAnonymizeIP() { return anonymizeIP; } + + public void setAnonymizeIP(boolean anonymizeIP) { this.anonymizeIP = anonymizeIP; } + @Override public boolean equals(Object other) { if (!(other instanceof Conversion)) @@ -192,6 +198,7 @@ public String toString() { ", eventMetrics=" + eventMetrics + ", eventFeatures=" + eventFeatures + ", isGlobalHoldback=" + isGlobalHoldback + + ", anonymizeIP=" + anonymizeIP + ", clientEngine='" + clientEngine + ", clientVersion='" + clientVersion + '}'; } diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Impression.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Impression.java index 92291c373..a4d3487fd 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Impression.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Impression.java @@ -28,11 +28,12 @@ public class Impression extends Event { private String layerId; private String accountId; private List userFeatures; + private boolean anonymizeIP; public Impression() { } public Impression(String visitorId, long timestamp, boolean isGlobalHoldback, String projectId, Decision decision, - String layerId, String accountId, List userFeatures) { + String layerId, String accountId, List userFeatures, boolean anonymizeIP) { this.visitorId = visitorId; this.timestamp = timestamp; this.isGlobalHoldback = isGlobalHoldback; @@ -41,6 +42,7 @@ public Impression(String visitorId, long timestamp, boolean isGlobalHoldback, St this.layerId = layerId; this.accountId = accountId; this.userFeatures = userFeatures; + this.anonymizeIP = anonymizeIP; } public String getVisitorId() { @@ -107,6 +109,14 @@ public void setUserFeatures(List userFeatures) { this.userFeatures = userFeatures; } + public boolean getAnonymizeIP() { + return anonymizeIP; + } + + public void setAnonymizeIP(boolean anonymizeIP) { + this.anonymizeIP = anonymizeIP; + } + @Override public boolean equals(Object other) { if (!(other instanceof Impression)) @@ -147,6 +157,7 @@ public String toString() { "visitorId='" + visitorId + '\'' + ", timestamp=" + timestamp + ", isGlobalHoldback=" + isGlobalHoldback + + ", anonymizeIP=" + anonymizeIP + ", projectId='" + projectId + '\'' + ", decision=" + decision + ", layerId='" + layerId + '\'' + diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/serializer/JsonSimpleSerializer.java b/core-api/src/main/java/com/optimizely/ab/event/internal/serializer/JsonSimpleSerializer.java index 5727b49b1..22f7671c7 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/serializer/JsonSimpleSerializer.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/serializer/JsonSimpleSerializer.java @@ -48,6 +48,7 @@ private JSONObject serializeImpression(Impression impression) { jsonObject.put("visitorId", impression.getVisitorId()); jsonObject.put("timestamp", impression.getTimestamp()); jsonObject.put("isGlobalHoldback", impression.getIsGlobalHoldback()); + jsonObject.put("anonymizeIP", impression.getAnonymizeIP()); jsonObject.put("projectId", impression.getProjectId()); jsonObject.put("decision", serializeDecision(impression.getDecision())); jsonObject.put("layerId", impression.getLayerId()); @@ -72,6 +73,7 @@ private JSONObject serializeConversion(Conversion conversion) { jsonObject.put("eventMetrics", serializeEventMetrics(conversion.getEventMetrics())); jsonObject.put("eventFeatures", serializeFeatures(conversion.getEventFeatures())); jsonObject.put("isGlobalHoldback", conversion.getIsGlobalHoldback()); + jsonObject.put("anonymizeIP", conversion.getAnonymizeIP()); jsonObject.put("clientEngine", conversion.getClientEngine()); jsonObject.put("clientVersion", conversion.getClientVersion()); diff --git a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTest.java b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTest.java index ef5726264..156ccf06f 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTest.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTest.java @@ -30,6 +30,7 @@ import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; @@ -179,4 +180,15 @@ public void verifyGetVariationToLiveVariableUsageInstanceMapping() throws Except assertThat(projectConfig.getVariationToLiveVariableUsageInstanceMapping(), is(expectedVariationToLiveVariableUsageInstanceMapping)); } + + /** + * Asserts that anonymizeIP is set to false if not explicitly passed into the constructor (in the case of V1 or V2 + * projects). + * @throws Exception + */ + @Test + public void verifyAnonymizeIPIsFalseByDefault() throws Exception { + ProjectConfig v2ProjectConfig = ProjectConfigTestUtils.validProjectConfigV2(); + assertFalse(v2ProjectConfig.getAnonymizeIP()); + } } \ No newline at end of file diff --git a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java index 3d380b11c..009b68f1f 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java @@ -437,7 +437,7 @@ private static ProjectConfig generateValidProjectConfigV3() { ); return new ProjectConfig("789", "1234", "3", "42", groups, experiments, attributes, events, audiences, - liveVariables); + true, liveVariables); } private static final ProjectConfig NO_AUDIENCE_PROJECT_CONFIG_V3 = generateNoAudienceProjectConfigV3(); @@ -474,7 +474,7 @@ private static ProjectConfig generateNoAudienceProjectConfigV3() { new EventType("099", "clicked_purchase", multipleExperimentIds)); return new ProjectConfig("789", "1234", "3", "42", Collections.emptyList(), experiments, attributes, - events, Collections.emptyList(), Collections.emptyList()); + events, Collections.emptyList(), true, Collections.emptyList()); } private ProjectConfigTestUtils() { } diff --git a/core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderV2Test.java b/core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderV2Test.java index 958203e0c..1c507bec7 100644 --- a/core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderV2Test.java +++ b/core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderV2Test.java @@ -90,6 +90,7 @@ public void createImpressionEvent() throws Exception { assertThat(impression.getVisitorId(), is(userId)); assertThat((double)impression.getTimestamp(), closeTo((double)System.currentTimeMillis(), 60.0)); assertFalse(impression.getIsGlobalHoldback()); + assertThat(impression.getAnonymizeIP(), is(projectConfig.getAnonymizeIP())); assertThat(impression.getProjectId(), is(projectConfig.getProjectId())); assertThat(impression.getDecision(), is(expectedDecision)); assertThat(impression.getLayerId(), is(activatedExperiment.getLayerId())); @@ -207,6 +208,7 @@ public void createConversionEvent() throws Exception { assertThat(conversion.getEventMetrics(), is(Collections.emptyList())); assertThat(conversion.getEventFeatures(), is(Collections.emptyList())); assertFalse(conversion.getIsGlobalHoldback()); + assertThat(conversion.getAnonymizeIP(), is(projectConfig.getAnonymizeIP())); assertThat(conversion.getClientEngine(), is(ClientEngine.JAVA_SDK.getClientEngineValue())); assertThat(conversion.getClientVersion(), is(BuildVersionInfo.VERSION)); } diff --git a/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java b/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java index 86c9d66fa..b4f7e70f7 100644 --- a/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java +++ b/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java @@ -73,6 +73,7 @@ static Impression generateImpression() { impression.setDecision(decision); impression.setUserFeatures(userFeatures); impression.setClientVersion("0.1.1"); + impression.setAnonymizeIP(true); return impression; } @@ -91,6 +92,7 @@ static Conversion generateConversion() { conversion.setEventFeatures(eventFeatures); conversion.setIsGlobalHoldback(isGlobalHoldback); conversion.setClientVersion("0.1.1"); + conversion.setAnonymizeIP(true); return conversion; } diff --git a/core-api/src/test/resources/config/valid-project-config-v3.json b/core-api/src/test/resources/config/valid-project-config-v3.json index db8f7bc34..a12dc22e7 100644 --- a/core-api/src/test/resources/config/valid-project-config-v3.json +++ b/core-api/src/test/resources/config/valid-project-config-v3.json @@ -3,6 +3,7 @@ "projectId": "1234", "version": "3", "revision": "42", + "anonymizeIP": true, "experiments": [ { "id": "223", diff --git a/core-api/src/test/resources/serializer/conversion.json b/core-api/src/test/resources/serializer/conversion.json index 2e4f86e67..0a9ceacfd 100644 --- a/core-api/src/test/resources/serializer/conversion.json +++ b/core-api/src/test/resources/serializer/conversion.json @@ -33,6 +33,7 @@ ], "eventFeatures": [], "isGlobalHoldback": false, + "anonymizeIP": true, "clientEngine": "java-sdk", "clientVersion": "0.1.1" } \ No newline at end of file diff --git a/core-api/src/test/resources/serializer/impression.json b/core-api/src/test/resources/serializer/impression.json index 2cfe69b06..cb1900f57 100644 --- a/core-api/src/test/resources/serializer/impression.json +++ b/core-api/src/test/resources/serializer/impression.json @@ -2,6 +2,7 @@ "visitorId": "testvisitor", "timestamp": 12345, "isGlobalHoldback": false, + "anonymizeIP": true, "projectId": "1", "decision": { "variationId": "4",