Skip to content
This repository has been archived by the owner on May 30, 2024. It is now read-only.

Commit

Permalink
prepare 5.4.0 release (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaunchDarklyCI authored Apr 22, 2021
1 parent e0bb18a commit 6ad64db
Show file tree
Hide file tree
Showing 14 changed files with 311 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ jobs:
- run: cat gradle.properties.example >>gradle.properties
- run:
name: checkstyle/javadoc
command: ./gradlew checkstyleMain
command: ./gradlew javadoc checkstyleMain
- run:
name: build all SDK jars
command: ./gradlew publishToMavenLocal -P LD_SKIP_SIGNING=1
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ ext.versions = [
"gson": "2.7",
"guava": "30.1-jre",
"jackson": "2.11.2",
"launchdarklyJavaSdkCommon": "1.0.0",
"launchdarklyJavaSdkCommon": "1.1.1",
"okhttp": "4.8.1", // specify this for the SDK build instead of relying on the transitive dependency from okhttp-eventsource
"okhttpEventsource": "2.3.1",
"slf4j": "1.7.21",
Expand Down
14 changes: 13 additions & 1 deletion src/main/java/com/launchdarkly/sdk/server/EventFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ abstract Event.FeatureRequest newUnknownFeatureRequestEvent(
abstract Event.Custom newCustomEvent(String key, LDUser user, LDValue data, Double metricValue);

abstract Event.Identify newIdentifyEvent(LDUser user);


abstract Event.AliasEvent newAliasEvent(LDUser user, LDUser previousUser);

final Event.FeatureRequest newFeatureRequestEvent(
DataModel.FeatureFlag flag,
LDUser user,
Expand Down Expand Up @@ -166,6 +168,11 @@ Event.Custom newCustomEvent(String key, LDUser user, LDValue data, Double metric
Event.Identify newIdentifyEvent(LDUser user) {
return new Event.Identify(timestampFn.get(), user);
}

@Override
Event.AliasEvent newAliasEvent(LDUser user, LDUser previousUser) {
return new Event.AliasEvent(timestampFn.get(), user, previousUser);
}
}

static final class Disabled extends EventFactory {
Expand All @@ -191,6 +198,11 @@ final Custom newCustomEvent(String key, LDUser user, LDValue data, Double metric
final Identify newIdentifyEvent(LDUser user) {
return null;
}

@Override
Event.AliasEvent newAliasEvent(LDUser user, LDUser previousUser) {
return null;
}
}

private static boolean isExperiment(DataModel.FeatureFlag flag, EvaluationReason reason) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,38 @@ private final void writeOutputEvent(Event event, JsonWriter jw) throws IOExcepti
jw.value(fe.getPrereqOf());
}
writeEvaluationReason("reason", fe.getReason(), jw);
jw.endObject();
if (!fe.getContextKind().equals("user")) {
jw.name("contextKind").value(fe.getContextKind());
}
} else if (event instanceof Event.Identify) {
startEvent(event, "identify", event.getUser() == null ? null : event.getUser().getKey(), jw);
writeUser(event.getUser(), jw);
jw.endObject();
} else if (event instanceof Event.Custom) {
Event.Custom ce = (Event.Custom)event;
startEvent(event, "custom", ce.getKey(), jw);
writeUserOrKey(ce, false, jw);
writeLDValue("data", ce.getData(), jw);
if (!ce.getContextKind().equals("user")) {
jw.name("contextKind").value(ce.getContextKind());
}
if (ce.getMetricValue() != null) {
jw.name("metricValue");
jw.value(ce.getMetricValue());
}
jw.endObject();
} else if (event instanceof Event.Index) {
startEvent(event, "index", null, jw);
writeUser(event.getUser(), jw);
jw.endObject();
} else if (event instanceof Event.AliasEvent) {
Event.AliasEvent ae = (Event.AliasEvent)event;
startEvent(event, "alias", ae.getKey(), jw);
jw.name("contextKind").value(ae.getContextKind());
jw.name("previousKey").value(ae.getPreviousKey());
jw.name("previousContextKind").value(ae.getPreviousContextKind());
} else {
return;
}

jw.endObject();
}

private final void writeSummaryEvent(EventSummarizer.EventSummary summary, JsonWriter jw) throws IOException {
Expand Down
36 changes: 35 additions & 1 deletion src/main/java/com/launchdarkly/sdk/server/FeatureFlagsState.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,48 @@ static class JsonSerialization extends TypeAdapter<FeatureFlagsState> {
@Override
public void write(JsonWriter out, FeatureFlagsState state) throws IOException {
out.beginObject();

for (Map.Entry<String, LDValue> entry: state.flagValues.entrySet()) {
out.name(entry.getKey());
gsonInstance().toJson(entry.getValue(), LDValue.class, out);
}

out.name("$flagsState");
gsonInstance().toJson(state.flagMetadata, Map.class, out);
out.beginObject();
for (Map.Entry<String, FlagMetadata> entry: state.flagMetadata.entrySet()) {
out.name(entry.getKey());
FlagMetadata meta = entry.getValue();
out.beginObject();
// Here we're serializing FlagMetadata properties individually because if we rely on
// Gson's reflection mechanism, it won't reliably drop null properties (that only works
// if the destination really is Gson, not if a Jackson adapter is being used).
if (meta.variation != null) {
out.name("variation");
out.value(meta.variation.intValue());
}
if (meta.reason != null) {
out.name("reason");
gsonInstance().toJson(meta.reason, EvaluationReason.class, out);
}
if (meta.version != null) {
out.name("version");
out.value(meta.version.intValue());
}
if (meta.trackEvents != null) {
out.name("trackEvents");
out.value(meta.trackEvents.booleanValue());
}
if (meta.debugEventsUntilDate != null) {
out.name("debugEventsUntilDate");
out.value(meta.debugEventsUntilDate.longValue());
}
out.endObject();
}
out.endObject();

out.name("$valid");
out.value(state.valid);

out.endObject();
}

Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/launchdarkly/sdk/server/LDClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,11 @@ public String secureModeHash(LDUser user) {
return null;
}

@Override
public void alias(LDUser user, LDUser previousUser) {
this.eventProcessor.sendEvent(eventFactoryDefault.newAliasEvent(user, previousUser));
}

/**
* Returns the current version string of the client library.
* @return a version string conforming to Semantic Versioning (http://semver.org)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import org.slf4j.Logger;

import java.io.Closeable;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
Expand All @@ -17,7 +18,7 @@
* This is currently only used by PersistentDataStoreWrapper, but encapsulating it in its own class helps with
* clarity and also lets us reuse this logic in tests.
*/
final class PersistentDataStoreStatusManager {
final class PersistentDataStoreStatusManager implements Closeable {
private static final Logger logger = Loggers.DATA_STORE;
static final int POLL_INTERVAL_MS = 500; // visible for testing

Expand All @@ -42,6 +43,15 @@ final class PersistentDataStoreStatusManager {
this.scheduler = sharedExecutor;
}

public void close() {
synchronized (this) {
if (pollerFuture != null) {
pollerFuture.cancel(true);
pollerFuture = null;
}
}
}

void updateAvailability(boolean available) {
synchronized (this) {
if (lastAvailable == available) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ private static CacheBuilder<Object, Object> newCacheBuilder(

@Override
public void close() throws IOException {
statusManager.close();
core.close();
}

Expand Down
88 changes: 87 additions & 1 deletion src/main/java/com/launchdarkly/sdk/server/interfaces/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ public long getCreationDate() {
public LDUser getUser() {
return user;
}

/**
* Convert a user into a context kind string
* @param user the user to get the context kind from
* @return the context kind string
*/
private static final String computeContextKind(LDUser user) {
return user != null && user.isAnonymous() ? "anonymousUser" : "user";
}

/**
* A custom event created with {@link LDClientInterface#track(String, LDUser)} or one of its overloads.
Expand All @@ -48,6 +57,7 @@ public static final class Custom extends Event {
private final String key;
private final LDValue data;
private final Double metricValue;
private final String contextKind;

/**
* Constructs a custom event.
Expand All @@ -61,8 +71,9 @@ public static final class Custom extends Event {
public Custom(long timestamp, String key, LDUser user, LDValue data, Double metricValue) {
super(timestamp, user);
this.key = key;
this.data = data == null ? LDValue.ofNull() : data;
this.data = LDValue.normalize(data);
this.metricValue = metricValue;
this.contextKind = computeContextKind(user);
}

/**
Expand All @@ -88,6 +99,14 @@ public LDValue getData() {
public Double getMetricValue() {
return metricValue;
}

/**
* The context kind of the user that generated this event
* @return the context kind
*/
public String getContextKind() {
return contextKind;
}
}

/**
Expand Down Expand Up @@ -132,6 +151,7 @@ public static final class FeatureRequest extends Event {
private final long debugEventsUntilDate;
private final EvaluationReason reason;
private final boolean debug;
private final String contextKind;

/**
* Constructs a feature request event.
Expand Down Expand Up @@ -162,6 +182,7 @@ public FeatureRequest(long timestamp, String key, LDUser user, int version, int
this.debugEventsUntilDate = debugEventsUntilDate;
this.reason = reason;
this.debug = debug;
this.contextKind = computeContextKind(user);
}

/**
Expand Down Expand Up @@ -243,5 +264,70 @@ public EvaluationReason getReason() {
public boolean isDebug() {
return debug;
}

/**
* The context kind of the user that generated this event
* @return the context kind
*/
public String getContextKind() {
return contextKind;
}
}

/**
* An event generated by aliasing users
* @since 5.4.0
*/
public static final class AliasEvent extends Event {
private final String key;
private final String contextKind;
private final String previousKey;
private final String previousContextKind;

/**
* Constructs an alias event.
* @param timestamp when the event was created
* @param user the user being aliased to
* @param previousUser the user being aliased from
*/
public AliasEvent(long timestamp, LDUser user, LDUser previousUser) {
super(timestamp, user);
this.key = user.getKey();
this.contextKind = computeContextKind(user);
this.previousKey = previousUser.getKey();
this.previousContextKind = computeContextKind(previousUser);
}

/**
* Get the key of the user being aliased to
* @return the user key
*/
public String getKey() {
return key;
}

/**
* Get the kind of the user being aliased to
* @return the context kind
*/
public String getContextKind() {
return contextKind;
}

/**
* Get the key of the user being aliased from
* @return the previous user key
*/
public String getPreviousKey() {
return previousKey;
}

/**
* Get the kind of the user being aliased from
* @return the previous context kind
*/
public String getPreviousContextKind() {
return previousContextKind;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,23 @@ public interface LDClientInterface extends Closeable {
* For more info: <a href="https://github.com/launchdarkly/js-client#secure-mode">https://github.com/launchdarkly/js-client#secure-mode</a>
* @param user the user to be hashed along with the SDK key
* @return the hash, or null if the hash could not be calculated
*/
*/
String secureModeHash(LDUser user);

/**
* Associates two users for analytics purposes.
*
* This can be helpful in the situation where a person is represented by multiple
* LaunchDarkly users. This may happen, for example, when a person initially logs into
* an application-- the person might be represented by an anonymous user prior to logging
* in and a different user after logging in, as denoted by a different user key.
*
* @param user the newly identified user.
* @param previousUser the previously identified user.
* @since 5.4.0
*/
void alias(LDUser user, LDUser previousUser);

/**
* The current version string of the SDK.
* @return a string in Semantic Versioning 2.0.0 format
Expand Down
Loading

0 comments on commit 6ad64db

Please sign in to comment.