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

Commit 5fa0fc4

Browse files
prepare 5.2.3 release (#225)
1 parent 1116901 commit 5fa0fc4

File tree

6 files changed

+60
-18
lines changed

6 files changed

+60
-18
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,3 @@ We encourage pull requests and other contributions from the community. Check out
6868
* [docs.launchdarkly.com](https://docs.launchdarkly.com/ "LaunchDarkly Documentation") for our documentation and SDK reference guides
6969
* [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ "LaunchDarkly API Documentation") for our API documentation
7070
* [blog.launchdarkly.com](https://blog.launchdarkly.com/ "LaunchDarkly Blog Documentation") for the latest product updates
71-
* [Feature Flagging Guide](https://github.com/launchdarkly/featureflags/ "Feature Flagging Guide") for best practices and strategies

src/main/java/com/launchdarkly/sdk/server/integrations/FileDataSourceImpl.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.util.concurrent.CompletableFuture;
4242
import java.util.concurrent.Future;
4343
import java.util.concurrent.atomic.AtomicBoolean;
44+
import java.util.concurrent.atomic.AtomicInteger;
4445

4546
import static com.launchdarkly.sdk.server.DataModel.FEATURES;
4647
import static com.launchdarkly.sdk.server.DataModel.SEGMENTS;
@@ -212,9 +213,11 @@ public void stop() {
212213
*/
213214
static final class DataLoader {
214215
private final List<SourceInfo> sources;
216+
private final AtomicInteger lastVersion;
215217

216218
public DataLoader(List<SourceInfo> sources) {
217219
this.sources = new ArrayList<>(sources);
220+
this.lastVersion = new AtomicInteger(0);
218221
}
219222

220223
public Iterable<SourceInfo> getSources() {
@@ -223,24 +226,25 @@ public Iterable<SourceInfo> getSources() {
223226

224227
public void load(DataBuilder builder) throws FileDataException
225228
{
229+
int version = lastVersion.incrementAndGet();
226230
for (SourceInfo s: sources) {
227231
try {
228232
byte[] data = s.readData();
229233
FlagFileParser parser = FlagFileParser.selectForContent(data);
230234
FlagFileRep fileContents = parser.parse(new ByteArrayInputStream(data));
231235
if (fileContents.flags != null) {
232236
for (Map.Entry<String, LDValue> e: fileContents.flags.entrySet()) {
233-
builder.add(FEATURES, e.getKey(), FlagFactory.flagFromJson(e.getValue()));
237+
builder.add(FEATURES, e.getKey(), FlagFactory.flagFromJson(e.getValue(), version));
234238
}
235239
}
236240
if (fileContents.flagValues != null) {
237241
for (Map.Entry<String, LDValue> e: fileContents.flagValues.entrySet()) {
238-
builder.add(FEATURES, e.getKey(), FlagFactory.flagWithValue(e.getKey(), e.getValue()));
242+
builder.add(FEATURES, e.getKey(), FlagFactory.flagWithValue(e.getKey(), e.getValue(), version));
239243
}
240244
}
241245
if (fileContents.segments != null) {
242246
for (Map.Entry<String, LDValue> e: fileContents.segments.entrySet()) {
243-
builder.add(SEGMENTS, e.getKey(), FlagFactory.segmentFromJson(e.getValue()));
247+
builder.add(SEGMENTS, e.getKey(), FlagFactory.segmentFromJson(e.getValue(), version));
244248
}
245249
}
246250
} catch (FileDataException e) {

src/main/java/com/launchdarkly/sdk/server/integrations/FileDataSourceParsing.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.google.gson.JsonObject;
66
import com.google.gson.JsonSyntaxException;
77
import com.launchdarkly.sdk.LDValue;
8+
import com.launchdarkly.sdk.ObjectBuilder;
89
import com.launchdarkly.sdk.server.integrations.FileDataSourceBuilder.SourceInfo;
910
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.ItemDescriptor;
1011

@@ -176,21 +177,18 @@ public FlagFileRep parse(InputStream input) throws FileDataException, IOExceptio
176177
static abstract class FlagFactory {
177178
private FlagFactory() {}
178179

179-
static ItemDescriptor flagFromJson(String jsonString) {
180-
return FEATURES.deserialize(jsonString);
181-
}
182-
183-
static ItemDescriptor flagFromJson(LDValue jsonTree) {
184-
return flagFromJson(jsonTree.toJsonString());
180+
static ItemDescriptor flagFromJson(LDValue jsonTree, int version) {
181+
return FEATURES.deserialize(replaceVersion(jsonTree, version).toJsonString());
185182
}
186183

187184
/**
188185
* Constructs a flag that always returns the same value. This is done by giving it a single
189186
* variation and setting the fallthrough variation to that.
190187
*/
191-
static ItemDescriptor flagWithValue(String key, LDValue jsonValue) {
188+
static ItemDescriptor flagWithValue(String key, LDValue jsonValue, int version) {
192189
LDValue o = LDValue.buildObject()
193190
.put("key", key)
191+
.put("version", version)
194192
.put("on", true)
195193
.put("variations", LDValue.buildArray().add(jsonValue).build())
196194
.put("fallthrough", LDValue.buildObject().put("variation", 0).build())
@@ -200,12 +198,17 @@ static ItemDescriptor flagWithValue(String key, LDValue jsonValue) {
200198
return FEATURES.deserialize(o.toJsonString());
201199
}
202200

203-
static ItemDescriptor segmentFromJson(String jsonString) {
204-
return SEGMENTS.deserialize(jsonString);
201+
static ItemDescriptor segmentFromJson(LDValue jsonTree, int version) {
202+
return SEGMENTS.deserialize(replaceVersion(jsonTree, version).toJsonString());
205203
}
206204

207-
static ItemDescriptor segmentFromJson(LDValue jsonTree) {
208-
return segmentFromJson(jsonTree.toJsonString());
205+
private static LDValue replaceVersion(LDValue objectValue, int version) {
206+
ObjectBuilder b = LDValue.buildObject();
207+
for (String key: objectValue.keys()) {
208+
b.put(key, objectValue.get(key));
209+
}
210+
b.put("version", version);
211+
return b.build();
209212
}
210213
}
211214
}

src/main/java/com/launchdarkly/sdk/server/interfaces/FlagTracker.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ public interface FlagTracker {
2525
* previously returned for some user. If you want to track flag value changes, use
2626
* {@link #addFlagValueChangeListener(String, LDUser, FlagValueChangeListener)} instead.
2727
* <p>
28+
* If using the file data source ({@link com.launchdarkly.sdk.server.integrations.FileData}), any change in
29+
* a data file will be treated as a change to every flag. Again, use
30+
* {@link #addFlagValueChangeListener(String, LDUser, FlagValueChangeListener)} (or just re-evaluate the flag
31+
* yourself) if you want to know whether this is a change that really affects a flag's value.
32+
* <p>
2833
* Change events only work if the SDK is actually connecting to LaunchDarkly (or using the file data source).
2934
* If the SDK is only reading flags from a database ({@link Components#externalUpdatesOnly()}) then it cannot
3035
* know when there is a change, because flags are read on an as-needed basis.

src/test/java/com/launchdarkly/sdk/server/integrations/ClientWithFileDataSourceTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import com.launchdarkly.sdk.server.Components;
66
import com.launchdarkly.sdk.server.LDClient;
77
import com.launchdarkly.sdk.server.LDConfig;
8-
import com.launchdarkly.sdk.server.integrations.FileData;
9-
import com.launchdarkly.sdk.server.integrations.FileDataSourceBuilder;
108

119
import org.junit.Test;
1210

src/test/java/com/launchdarkly/sdk/server/integrations/DataLoaderTest.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import com.google.gson.Gson;
44
import com.google.gson.JsonElement;
55
import com.google.gson.JsonObject;
6+
import com.launchdarkly.sdk.LDValue;
67
import com.launchdarkly.sdk.server.integrations.FileDataSourceImpl.DataBuilder;
78
import com.launchdarkly.sdk.server.integrations.FileDataSourceImpl.DataLoader;
89
import com.launchdarkly.sdk.server.integrations.FileDataSourceParsing.FileDataException;
910
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.DataKind;
11+
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.FullDataSet;
1012
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.ItemDescriptor;
13+
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.KeyedItems;
1114

1215
import org.junit.Assert;
1316
import org.junit.Test;
@@ -74,7 +77,7 @@ public void flagValueIsConvertedToFlag() throws Exception {
7477
DataLoader ds = new DataLoader(FileData.dataSource().filePaths(resourceFilePath("value-only.json")).sources);
7578
JsonObject expected = gson.fromJson(
7679
"{\"key\":\"flag2\",\"on\":true,\"fallthrough\":{\"variation\":0},\"variations\":[\"value2\"]," +
77-
"\"trackEvents\":false,\"deleted\":false,\"version\":0}",
80+
"\"trackEvents\":false,\"deleted\":false,\"version\":1}",
7881
JsonObject.class);
7982
ds.load(builder);
8083
ItemDescriptor flag = toDataMap(builder.build()).get(FEATURES).get(FLAG_VALUE_1_KEY);
@@ -125,10 +128,40 @@ public void duplicateSegmentKeyThrowsException() throws Exception {
125128
}
126129
}
127130

131+
@Test
132+
public void versionsAreIncrementedForEachLoad() throws Exception {
133+
DataLoader ds = new DataLoader(FileData.dataSource().filePaths(
134+
resourceFilePath("flag-only.json"),
135+
resourceFilePath("segment-only.json"),
136+
resourceFilePath("value-only.json")
137+
).sources);
138+
139+
DataBuilder data1 = new DataBuilder();
140+
ds.load(data1);
141+
assertVersionsMatch(data1.build(), 1);
142+
143+
DataBuilder data2 = new DataBuilder();
144+
ds.load(data2);
145+
assertVersionsMatch(data2.build(), 2);
146+
}
147+
128148
private void assertDataHasItemsOfKind(DataKind kind) {
129149
Map<String, ItemDescriptor> items = toDataMap(builder.build()).get(kind);
130150
if (items == null || items.size() == 0) {
131151
Assert.fail("expected at least one item in \"" + kind.getName() + "\", received: " + builder.build());
132152
}
133153
}
154+
155+
private void assertVersionsMatch(FullDataSet<ItemDescriptor> data, int expectedVersion) {
156+
for (Map.Entry<DataKind, KeyedItems<ItemDescriptor>> kv1: data.getData()) {
157+
DataKind kind = kv1.getKey();
158+
for (Map.Entry<String, ItemDescriptor> kv2: kv1.getValue().getItems()) {
159+
ItemDescriptor item = kv2.getValue();
160+
String jsonData = kind.serialize(item);
161+
assertThat("descriptor version of " + kv2.getKey(), item.getVersion(), equalTo(expectedVersion));
162+
assertThat("version in data model object of " + kv2.getKey(), LDValue.parse(jsonData).get("version"),
163+
equalTo(LDValue.of(expectedVersion)));
164+
}
165+
}
166+
}
134167
}

0 commit comments

Comments
 (0)