From 1fb5b237d780cae0adb66a42705ace16db7ee010 Mon Sep 17 00:00:00 2001 From: Dan Richelson Date: Thu, 26 May 2016 10:32:46 -0700 Subject: [PATCH 1/4] Update Javadoc when setting custom attributes for users. --- src/main/java/com/launchdarkly/client/LDUser.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/launchdarkly/client/LDUser.java b/src/main/java/com/launchdarkly/client/LDUser.java index ec40dbd47..2d491a2b5 100644 --- a/src/main/java/com/launchdarkly/client/LDUser.java +++ b/src/main/java/com/launchdarkly/client/LDUser.java @@ -33,7 +33,6 @@ public class LDUser { private JsonPrimitive firstName; private JsonPrimitive lastName; private JsonPrimitive anonymous; - private JsonPrimitive country; private Map custom; private static final Logger logger = LoggerFactory.getLogger(LDUser.class); @@ -248,8 +247,8 @@ public Builder email(String email) { } /** - * Add a {@link java.lang.String}-valued custom attribute - * @param k the key for the custom attribute + * Add a {@link java.lang.String}-valued custom attribute. + * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param v the value for the custom attribute * @return the builder */ @@ -262,7 +261,7 @@ public Builder custom(String k, String v) { /** * Add a {@link java.lang.Number}-valued custom attribute - * @param k the key for the custom attribute + * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param n the value for the custom attribute * @return the builder */ @@ -275,7 +274,7 @@ public Builder custom(String k, Number n) { /** * Add a {@link java.lang.Boolean}-valued custom attribute - * @param k the key for the custom attribute + * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param b the value for the custom attribute * @return the builder */ @@ -288,7 +287,7 @@ public Builder custom(String k, Boolean b) { /** * Add a list of {@link java.lang.String}-valued custom attributes - * @param k the key for the list + * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute * @return the builder * @deprecated As of version 0.16.0, renamed to {@link #customString(String, List) customString} @@ -299,7 +298,7 @@ public Builder custom(String k, List vs) { /** * Add a list of {@link java.lang.String}-valued custom attributes - * @param k the key for the list + * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute * @return the builder */ @@ -316,7 +315,7 @@ public Builder customString(String k, List vs) { /** * Add a list of {@link java.lang.Integer}-valued custom attributes - * @param k the key for the list + * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute * @return the builder */ From 1f24ce7a95ba1f9bf3d2c1e79af26d9667761302 Mon Sep 17 00:00:00 2001 From: Dan Richelson Date: Thu, 26 May 2016 12:40:51 -0700 Subject: [PATCH 2/4] Add check when adding custom attribute with same key as built-in attribute. Fix formatting. Fix null check in user builder. --- .../java/com/launchdarkly/client/LDUser.java | 105 +++++++++++++----- .../launchdarkly/client/UserAttribute.java | 14 +++ 2 files changed, 90 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/launchdarkly/client/UserAttribute.java diff --git a/src/main/java/com/launchdarkly/client/LDUser.java b/src/main/java/com/launchdarkly/client/LDUser.java index 2d491a2b5..a3a993f42 100644 --- a/src/main/java/com/launchdarkly/client/LDUser.java +++ b/src/main/java/com/launchdarkly/client/LDUser.java @@ -15,11 +15,11 @@ * A {@code LDUser} object contains specific attributes of a user browsing your site. The only mandatory property property is the {@code key}, * which must uniquely identify each user. For authenticated users, this may be a username or e-mail address. For anonymous users, * this could be an IP address or session ID. - * + *

* Besides the mandatory {@code key}, {@code LDUser} supports two kinds of optional attributes: interpreted attributes (e.g. {@code ip} and {@code country}) * and custom attributes. LaunchDarkly can parse interpreted attributes and attach meaning to them. For example, from an {@code ip} address, LaunchDarkly can * do a geo IP lookup and determine the user's country. - * + *

* Custom attributes are not parsed by LaunchDarkly. They can be used in custom rules-- for example, a custom attribute such as "customer_ranking" can be used to * launch a feature to the top 10% of users on a site. */ @@ -43,21 +43,22 @@ public class LDUser { } protected LDUser(Builder builder) { - this.key = builder.key == null? null : new JsonPrimitive(builder.key); - this.ip = builder.ip == null? null : new JsonPrimitive(builder.ip); - this.country = builder.country == null? null : new JsonPrimitive(builder.country.getAlpha2()); + this.key = builder.key == null ? null : new JsonPrimitive(builder.key); + this.ip = builder.ip == null ? null : new JsonPrimitive(builder.ip); + this.country = builder.country == null ? null : new JsonPrimitive(builder.country.getAlpha2()); this.secondary = builder.secondary == null ? null : new JsonPrimitive(builder.secondary); this.firstName = builder.firstName == null ? null : new JsonPrimitive(builder.firstName); this.lastName = builder.lastName == null ? null : new JsonPrimitive(builder.lastName); this.email = builder.email == null ? null : new JsonPrimitive(builder.email); this.name = builder.name == null ? null : new JsonPrimitive(builder.name); this.avatar = builder.avatar == null ? null : new JsonPrimitive(builder.avatar); - this.anonymous = builder.anonymous == null ? null : new JsonPrimitive(builder.anonymous); + this.anonymous = builder.anonymous == null ? null : new JsonPrimitive(builder.anonymous); this.custom = new HashMap<>(builder.custom); } /** * Create a user with the given key + * * @param key a {@code String} that uniquely identifies a user */ public LDUser(String key) { @@ -69,23 +70,41 @@ JsonPrimitive getKey() { return key; } - JsonPrimitive getIp() { return ip; } + JsonPrimitive getIp() { + return ip; + } - JsonPrimitive getCountry() { return country; } + JsonPrimitive getCountry() { + return country; + } - JsonPrimitive getSecondary() { return secondary; } + JsonPrimitive getSecondary() { + return secondary; + } - JsonPrimitive getName() { return name; } + JsonPrimitive getName() { + return name; + } - JsonPrimitive getFirstName() { return firstName; } + JsonPrimitive getFirstName() { + return firstName; + } - JsonPrimitive getLastName() { return lastName; } + JsonPrimitive getLastName() { + return lastName; + } - JsonPrimitive getEmail() { return email; } + JsonPrimitive getEmail() { + return email; + } - JsonPrimitive getAvatar() { return avatar; } + JsonPrimitive getAvatar() { + return avatar; + } - JsonPrimitive getAnonymous() { return anonymous; } + JsonPrimitive getAnonymous() { + return anonymous; + } JsonElement getCustom(String key) { return custom.get(key); @@ -94,14 +113,13 @@ JsonElement getCustom(String key) { /** * A builder that helps construct {@link com.launchdarkly.client.LDUser} objects. Builder * calls can be chained, enabling the following pattern: - * + *

*

    * LDUser user = new LDUser.Builder("key")
    *      .country("US")
    *      .ip("192.168.0.1")
    *      .build()
    * 
- * */ public static class Builder { private String key; @@ -118,6 +136,7 @@ public static class Builder { /** * Create a builder with the specified key + * * @param key the unique key for this user */ public Builder(String key) { @@ -127,6 +146,7 @@ public Builder(String key) { /** * Set the IP for a user + * * @param s the IP address for the user * @return the builder */ @@ -144,6 +164,7 @@ public Builder secondary(String s) { * Set the country for a user. The country should be a valid ISO 3166-1 * alpha-2 or alpha-3 code. If it is not a valid ISO-3166-1 code, an attempt will be made to look up the country by its name. * If that fails, a warning will be logged, and the country will not be set. + * * @param s the country for the user * @return the builder */ @@ -155,8 +176,7 @@ public Builder country(String s) { if (codes.isEmpty()) { logger.warn("Invalid country. Expected valid ISO-3166-1 code: " + s); - } - else if (codes.size() > 1) { + } else if (codes.size() > 1) { // See if any of the codes is an exact match for (LDCountryCode c : codes) { if (c.getName().equals(s)) { @@ -166,8 +186,7 @@ else if (codes.size() > 1) { } logger.warn("Ambiguous country. Provided code matches multiple countries: " + s); country = codes.get(0); - } - else { + } else { country = codes.get(0); } @@ -188,6 +207,7 @@ public Builder country(LDCountryCode country) { /** * Sets the user's first name + * * @param firstName the user's first name * @return the builder */ @@ -198,6 +218,7 @@ public Builder firstName(String firstName) { /** * Sets whether this user is anonymous + * * @param anonymous whether the user is anonymous * @return the builder */ @@ -208,6 +229,7 @@ public Builder anonymous(boolean anonymous) { /** * Sets the user's last name + * * @param lastName the user's last name * @return the builder */ @@ -218,6 +240,7 @@ public Builder lastName(String lastName) { /** * Sets the user's full name + * * @param name the user's full name * @return the builder */ @@ -228,6 +251,7 @@ public Builder name(String name) { /** * Sets the user's avatar + * * @param avatar the user's avatar * @return the builder */ @@ -238,6 +262,7 @@ public Builder avatar(String avatar) { /** * Sets the user's e-mail address + * * @param email the e-mail address * @return the builder */ @@ -248,12 +273,14 @@ public Builder email(String email) { /** * Add a {@link java.lang.String}-valued custom attribute. + * * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param v the value for the custom attribute * @return the builder */ public Builder custom(String k, String v) { - if (key != null && v != null) { + checkCustomAttribute(k); + if (k != null && v != null) { custom.put(k, new JsonPrimitive(v)); } return this; @@ -261,12 +288,14 @@ public Builder custom(String k, String v) { /** * Add a {@link java.lang.Number}-valued custom attribute + * * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param n the value for the custom attribute * @return the builder */ public Builder custom(String k, Number n) { - if (key != null && n != null) { + checkCustomAttribute(k); + if (k != null && n != null) { custom.put(k, new JsonPrimitive(n)); } return this; @@ -274,12 +303,14 @@ public Builder custom(String k, Number n) { /** * Add a {@link java.lang.Boolean}-valued custom attribute + * * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param b the value for the custom attribute * @return the builder */ public Builder custom(String k, Boolean b) { - if (key != null && b != null) { + checkCustomAttribute(k); + if (k != null && b != null) { custom.put(k, new JsonPrimitive(b)); } return this; @@ -287,22 +318,26 @@ public Builder custom(String k, Boolean b) { /** * Add a list of {@link java.lang.String}-valued custom attributes - * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. + * + * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute * @return the builder * @deprecated As of version 0.16.0, renamed to {@link #customString(String, List) customString} */ public Builder custom(String k, List vs) { + checkCustomAttribute(k); return this.customString(k, vs); } - + /** * Add a list of {@link java.lang.String}-valued custom attributes - * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. + * + * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute * @return the builder */ public Builder customString(String k, List vs) { + checkCustomAttribute(k); JsonArray array = new JsonArray(); for (String v : vs) { if (v != null) { @@ -312,14 +347,16 @@ public Builder customString(String k, List vs) { custom.put(k, array); return this; } - + /** * Add a list of {@link java.lang.Integer}-valued custom attributes - * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. + * + * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute * @return the builder */ public Builder customNumber(String k, List vs) { + checkCustomAttribute(k); JsonArray array = new JsonArray(); for (Number v : vs) { if (v != null) { @@ -330,8 +367,18 @@ public Builder customNumber(String k, List vs) { return this; } + private void checkCustomAttribute(String key) { + for (UserAttribute a : UserAttribute.values()) { + if (a.name().equals(key)) { + logger.warn("Built-in attribute key: " + key + " added as custom attribute! This custom attribute will be ignored during Feature Flag evaluation"); + return; + } + } + } + /** * Build the configured {@link com.launchdarkly.client.LDUser} object + * * @return the {@link com.launchdarkly.client.LDUser} configured by this builder */ public LDUser build() { diff --git a/src/main/java/com/launchdarkly/client/UserAttribute.java b/src/main/java/com/launchdarkly/client/UserAttribute.java new file mode 100644 index 000000000..73337288a --- /dev/null +++ b/src/main/java/com/launchdarkly/client/UserAttribute.java @@ -0,0 +1,14 @@ +package com.launchdarkly.client; + +public enum UserAttribute { + key, + secondary, + ip, + email, + name, + avatar, + firstName, + lastName, + anonymous, + country; +} From a7d3db2b910f8ad907d14ebb75cf8761fb36b973 Mon Sep 17 00:00:00 2001 From: Dan Richelson Date: Thu, 26 May 2016 13:03:23 -0700 Subject: [PATCH 3/4] Address PR comment --- .../launchdarkly/client/UserAttribute.java | 4 +- .../com/launchdarkly/client/ManualTest.java | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/launchdarkly/client/ManualTest.java diff --git a/src/main/java/com/launchdarkly/client/UserAttribute.java b/src/main/java/com/launchdarkly/client/UserAttribute.java index 73337288a..8b024e741 100644 --- a/src/main/java/com/launchdarkly/client/UserAttribute.java +++ b/src/main/java/com/launchdarkly/client/UserAttribute.java @@ -1,6 +1,6 @@ package com.launchdarkly.client; -public enum UserAttribute { +enum UserAttribute { key, secondary, ip, @@ -10,5 +10,5 @@ public enum UserAttribute { firstName, lastName, anonymous, - country; + country } diff --git a/src/test/java/com/launchdarkly/client/ManualTest.java b/src/test/java/com/launchdarkly/client/ManualTest.java new file mode 100644 index 000000000..d84065009 --- /dev/null +++ b/src/test/java/com/launchdarkly/client/ManualTest.java @@ -0,0 +1,38 @@ +package com.launchdarkly.client; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.net.URISyntaxException; + +@Ignore +public class ManualTest { + private static final Logger logger = LoggerFactory.getLogger(ManualTest.class); + + @Test + public void manualTest() throws URISyntaxException { + LDConfig config = new LDConfig.Builder() + .startWaitMillis(30000L) + .baseURI(URI.create("https://ld-stg.global.ssl.fastly.net")) +// .streamURI(URI.create("https://f6bff885.fanoutcdn.com")) +// .eventsURI(URI.create("https://events-stg.launchdarkly.com")) + .stream(false) + .build(); + + //my prod key: +// LDClient ldClient = new LDClient("sdk-fdd9a27d-7939-41a1-bf36-b64798d93372", config); + + //staging + LDClient ldClient = new LDClient("sdk-0b5766c3-50fa-427e-be3b-50fd3c631c5d", config); + + LDUser user = new LDUser.Builder("user1Key").build(); + System.out.println(ldClient.toggle("abc", user, false)); + + +// while (true) { +// } + } +} From 9a82022281ca7dd162d834617090e0b6246f9558 Mon Sep 17 00:00:00 2001 From: Dan Richelson Date: Sat, 28 May 2016 13:41:01 -0700 Subject: [PATCH 4/4] Add link to built-in attributes in comments. Revert accidentally committed manual test file. --- .../java/com/launchdarkly/client/LDUser.java | 27 +++++++++---- .../com/launchdarkly/client/ManualTest.java | 38 ------------------- 2 files changed, 20 insertions(+), 45 deletions(-) delete mode 100644 src/test/java/com/launchdarkly/client/ManualTest.java diff --git a/src/main/java/com/launchdarkly/client/LDUser.java b/src/main/java/com/launchdarkly/client/LDUser.java index a3a993f42..b857624ff 100644 --- a/src/main/java/com/launchdarkly/client/LDUser.java +++ b/src/main/java/com/launchdarkly/client/LDUser.java @@ -272,11 +272,14 @@ public Builder email(String email) { } /** - * Add a {@link java.lang.String}-valued custom attribute. + * Add a {@link java.lang.String}-valued custom attribute. When set to one of the + * + * built-in user attribute keys, this custom attribute will be ignored. * - * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. + * @param k the key for the custom attribute. * @param v the value for the custom attribute * @return the builder + * @see */ public Builder custom(String k, String v) { checkCustomAttribute(k); @@ -287,7 +290,9 @@ public Builder custom(String k, String v) { } /** - * Add a {@link java.lang.Number}-valued custom attribute + * Add a {@link java.lang.Number}-valued custom attribute. When set to one of the + * + * built-in user attribute keys, this custom attribute will be ignored. * * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param n the value for the custom attribute @@ -302,7 +307,9 @@ public Builder custom(String k, Number n) { } /** - * Add a {@link java.lang.Boolean}-valued custom attribute + * Add a {@link java.lang.Boolean}-valued custom attribute. When set to one of the + * + * built-in user attribute keys, this custom attribute will be ignored. * * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param b the value for the custom attribute @@ -317,7 +324,9 @@ public Builder custom(String k, Boolean b) { } /** - * Add a list of {@link java.lang.String}-valued custom attributes + * Add a list of {@link java.lang.String}-valued custom attributes. When set to one of the + * + * built-in user attribute keys, this custom attribute will be ignored. * * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute @@ -330,7 +339,9 @@ public Builder custom(String k, List vs) { } /** - * Add a list of {@link java.lang.String}-valued custom attributes + * Add a list of {@link java.lang.String}-valued custom attributes. When set to one of the + * + * built-in user attribute keys, this custom attribute will be ignored. * * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute @@ -349,7 +360,9 @@ public Builder customString(String k, List vs) { } /** - * Add a list of {@link java.lang.Integer}-valued custom attributes + * Add a list of {@link java.lang.Integer}-valued custom attributes. When set to one of the + * + * built-in user attribute keys, this custom attribute will be ignored. * * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored. * @param vs the values for the attribute diff --git a/src/test/java/com/launchdarkly/client/ManualTest.java b/src/test/java/com/launchdarkly/client/ManualTest.java deleted file mode 100644 index d84065009..000000000 --- a/src/test/java/com/launchdarkly/client/ManualTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.launchdarkly.client; - -import org.junit.Ignore; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.URI; -import java.net.URISyntaxException; - -@Ignore -public class ManualTest { - private static final Logger logger = LoggerFactory.getLogger(ManualTest.class); - - @Test - public void manualTest() throws URISyntaxException { - LDConfig config = new LDConfig.Builder() - .startWaitMillis(30000L) - .baseURI(URI.create("https://ld-stg.global.ssl.fastly.net")) -// .streamURI(URI.create("https://f6bff885.fanoutcdn.com")) -// .eventsURI(URI.create("https://events-stg.launchdarkly.com")) - .stream(false) - .build(); - - //my prod key: -// LDClient ldClient = new LDClient("sdk-fdd9a27d-7939-41a1-bf36-b64798d93372", config); - - //staging - LDClient ldClient = new LDClient("sdk-0b5766c3-50fa-427e-be3b-50fd3c631c5d", config); - - LDUser user = new LDUser.Builder("user1Key").build(); - System.out.println(ldClient.toggle("abc", user, false)); - - -// while (true) { -// } - } -}