Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/main/java/io/split/Spec.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ private Spec() {
}

// TODO: Change the schema to 1.3 when updating splitclient
public static String SPEC_VERSION = "1.1";
public static final String SPEC_1_3 = "1.3";
public static final String SPEC_1_1 = "1.1";
public static String SPEC_VERSION = SPEC_1_3;
}

40 changes: 26 additions & 14 deletions client/src/main/java/io/split/client/HttpSplitChangeFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

import com.google.common.annotations.VisibleForTesting;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.split.Spec;
import io.split.client.dtos.RuleBasedSegment;
import io.split.client.dtos.Split;
import io.split.client.dtos.SplitChange;
import io.split.client.dtos.SplitHttpResponse;
import io.split.client.exceptions.UriTooLongException;
import io.split.client.utils.GenericClientUtil;
import io.split.client.utils.Json;
import io.split.client.utils.Utils;
import io.split.engine.common.FetchOptions;
Expand All @@ -20,6 +26,7 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;

import static com.google.common.base.Preconditions.checkNotNull;
import static io.split.Spec.SPEC_VERSION;
Expand All @@ -31,6 +38,7 @@ public final class HttpSplitChangeFetcher implements SplitChangeFetcher {
private static final Logger _log = LoggerFactory.getLogger(HttpSplitChangeFetcher.class);

private static final String SINCE = "since";
private static final String RB_SINCE = "rbSince";
private static final String TILL = "till";
private static final String SETS = "sets";
private static final String SPEC = "s";
Expand All @@ -56,38 +64,42 @@ long makeRandomTill() {
}

@Override
public SplitChange fetch(long since, FetchOptions options) {

public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {
long start = System.currentTimeMillis();

try {
URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + SPEC_VERSION);
uriBuilder.addParameter(SINCE, "" + since);
if (!options.flagSetsFilter().isEmpty()) {
uriBuilder.addParameter(SETS, "" + options.flagSetsFilter());
}
if (options.hasCustomCN()) {
uriBuilder.addParameter(TILL, "" + options.targetCN());
}
URI uri = uriBuilder.build();
URI uri = buildURL(options, since, sinceRBS);
SplitHttpResponse response = _client.get(uri, options, null);

if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
if (response.statusCode() == HttpStatus.SC_REQUEST_URI_TOO_LONG) {
_log.error("The amount of flag sets provided are big causing uri length error.");
throw new UriTooLongException(String.format("Status code: %s. Message: %s", response.statusCode(), response.statusMessage()));
}

_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode());
throw new IllegalStateException(
String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode())
);
}
return Json.fromJson(response.body(), SplitChange.class);
return GenericClientUtil.ExtractFeatureFlagsAndRuleBasedSegments(response.body());
} catch (Exception e) {
throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e);
} finally {
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis()-start);
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start);
}
}

private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + SPEC_VERSION);
uriBuilder.addParameter(SINCE, "" + since);
uriBuilder.addParameter(RB_SINCE, "" + sinceRBS);
if (!options.flagSetsFilter().isEmpty()) {
uriBuilder.addParameter(SETS, "" + options.flagSetsFilter());
}
if (options.hasCustomCN()) {
uriBuilder.addParameter(TILL, "" + options.targetCN());
}
return uriBuilder.build();
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.split.client.utils.LocalhostSanitizer;
import io.split.engine.common.FetchOptions;
import io.split.engine.experiments.SplitChangeFetcher;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -15,6 +16,7 @@
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;

public class JsonLocalhostSplitChangeFetcher implements SplitChangeFetcher {
Expand All @@ -29,10 +31,13 @@ public JsonLocalhostSplitChangeFetcher(InputStreamProvider inputStreamProvider)
}

@Override
public SplitChange fetch(long since, FetchOptions options) {
public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {
try {
JsonReader jsonReader = new JsonReader(new BufferedReader(new InputStreamReader(_inputStreamProvider.get(), StandardCharsets.UTF_8)));
SplitChange splitChange = Json.fromJson(jsonReader, SplitChange.class);
splitChange.ruleBasedSegments = new ArrayList<>();
splitChange.tillRBS = -1;
splitChange.sinceRBS = -1;
return processSplitChange(splitChange, since);
} catch (Exception e) {
throw new IllegalStateException("Problem fetching splitChanges: " + e.getMessage(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public LegacyLocalhostSplitChangeFetcher(String directory) {
}

@Override
public SplitChange fetch(long since, FetchOptions options) {
public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {

try (BufferedReader reader = new BufferedReader(new FileReader(_splitFile))) {
SplitChange splitChange = new SplitChange();
Expand Down Expand Up @@ -82,6 +82,9 @@ public SplitChange fetch(long since, FetchOptions options) {
}
splitChange.till = since;
splitChange.since = since;
splitChange.sinceRBS = -1;
splitChange.tillRBS = -1;
splitChange.ruleBasedSegments = new ArrayList<>();
return splitChange;
} catch (FileNotFoundException f) {
_log.warn("There was no file named " + _splitFile.getPath() + " found. " +
Expand Down
14 changes: 10 additions & 4 deletions client/src/main/java/io/split/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import io.split.engine.experiments.SplitFetcherImp;
import io.split.engine.experiments.SplitParser;
import io.split.engine.experiments.SplitSynchronizationTask;
import io.split.engine.experiments.RuleBasedSegmentParser;
import io.split.engine.segments.SegmentChangeFetcher;
import io.split.engine.segments.SegmentSynchronizationTaskImp;
import io.split.integrations.IntegrationsConfig;
Expand All @@ -68,6 +69,7 @@
import io.split.storages.SplitCacheProducer;
import io.split.storages.RuleBasedSegmentCacheConsumer;
import io.split.storages.RuleBasedSegmentCache;
import io.split.storages.RuleBasedSegmentCacheProducer;
import io.split.storages.enums.OperationMode;
import io.split.storages.memory.InMemoryCacheImp;
import io.split.storages.memory.SegmentCacheInMemoryImpl;
Expand Down Expand Up @@ -220,8 +222,10 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn


SplitParser splitParser = new SplitParser();
RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser();
// SplitFetcher
_splitFetcher = buildSplitFetcher(splitCache, splitParser, flagSetsFilter);
_splitFetcher = buildSplitFetcher(splitCache, splitParser, flagSetsFilter,
ruleBasedSegmentParser, ruleBasedSegmentCache);

// SplitSynchronizationTask
_splitSynchronizationTask = new SplitSynchronizationTask(_splitFetcher,
Expand Down Expand Up @@ -422,9 +426,10 @@ protected SplitFactoryImpl(SplitClientConfig config) {
// SplitFetcher
SplitChangeFetcher splitChangeFetcher = createSplitChangeFetcher(config);
SplitParser splitParser = new SplitParser();
RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser();

_splitFetcher = new SplitFetcherImp(splitChangeFetcher, splitParser, splitCache, _telemetryStorageProducer,
flagSetsFilter);
flagSetsFilter, ruleBasedSegmentParser, _ruleBasedSegmentCache);

// SplitSynchronizationTask
_splitSynchronizationTask = new SplitSynchronizationTask(_splitFetcher, splitCache,
Expand Down Expand Up @@ -617,11 +622,12 @@ private SegmentSynchronizationTaskImp buildSegments(SplitClientConfig config,
}

private SplitFetcher buildSplitFetcher(SplitCacheProducer splitCacheProducer, SplitParser splitParser,
FlagSetsFilter flagSetsFilter) throws URISyntaxException {
FlagSetsFilter flagSetsFilter, RuleBasedSegmentParser ruleBasedSegmentParser,
RuleBasedSegmentCacheProducer ruleBasedSegmentCache) throws URISyntaxException {
SplitChangeFetcher splitChangeFetcher = HttpSplitChangeFetcher.create(_splitHttpClient, _rootTarget,
_telemetryStorageProducer);
return new SplitFetcherImp(splitChangeFetcher, splitParser, splitCacheProducer, _telemetryStorageProducer,
flagSetsFilter);
flagSetsFilter, ruleBasedSegmentParser, ruleBasedSegmentCache);
}

private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public YamlLocalhostSplitChangeFetcher(InputStreamProvider inputStreamProvider)
}

@Override
public SplitChange fetch(long since, FetchOptions options) {
public SplitChange fetch(long since, long sinceRBS, FetchOptions options) {
try {
Yaml yaml = new Yaml();
List<Map<String, Map<String, Object>>> yamlSplits = yaml.load(_inputStreamProvider.get());
Expand Down Expand Up @@ -73,6 +73,9 @@ public SplitChange fetch(long since, FetchOptions options) {
}
splitChange.till = since;
splitChange.since = since;
splitChange.sinceRBS = -1;
splitChange.tillRBS = -1;
splitChange.ruleBasedSegments = new ArrayList<>();
return splitChange;
} catch (Exception e) {
throw new IllegalStateException("Problem fetching splitChanges using a yaml file: " + e.getMessage(), e);
Expand Down
3 changes: 3 additions & 0 deletions client/src/main/java/io/split/client/dtos/SplitChange.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ public class SplitChange {
public List<Split> splits;
public long since;
public long till;
public List<RuleBasedSegment> ruleBasedSegments;
public long sinceRBS;
public long tillRBS;
}
27 changes: 27 additions & 0 deletions client/src/main/java/io/split/client/utils/GenericClientUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package io.split.client.utils;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.split.client.dtos.RuleBasedSegment;
import io.split.client.dtos.Split;
import io.split.client.dtos.SplitChange;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
Expand All @@ -8,6 +13,7 @@
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;

public class GenericClientUtil {
Expand Down Expand Up @@ -40,4 +46,25 @@ public static<T> void process(List<T> data, URI endpoint, CloseableHttpClient cl
}

}

public static SplitChange ExtractFeatureFlagsAndRuleBasedSegments(String responseBody) {
JsonObject jsonBody = Json.fromJson(responseBody, JsonObject.class);
JsonObject featureFlags = jsonBody.getAsJsonObject("ff");
JsonObject ruleBasedSegments = jsonBody.getAsJsonObject("rbs");
SplitChange splitChange = new SplitChange();
splitChange.till = Long.parseLong(featureFlags.get("t").toString());
splitChange.since = Long.parseLong(featureFlags.get("s").toString());
splitChange.tillRBS = Long.parseLong(ruleBasedSegments.get("t").toString());
splitChange.sinceRBS = Long.parseLong(ruleBasedSegments.get("s").toString());

splitChange.splits = new ArrayList<>();
for (JsonElement split: featureFlags.get("d").getAsJsonArray()) {
splitChange.splits.add(Json.fromJson(split.toString(), Split.class));
}
splitChange.ruleBasedSegments = new ArrayList<>();
for (JsonElement rbs: ruleBasedSegments.get("d").getAsJsonArray()) {
splitChange.ruleBasedSegments.add(Json.fromJson(rbs.toString(), RuleBasedSegment.class));
}
return splitChange;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.split.client.utils;

import io.split.client.dtos.RuleBasedSegment;
import io.split.client.dtos.Status;
import io.split.engine.experiments.ParsedRuleBasedSegment;
import io.split.engine.experiments.RuleBasedSegmentParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class RuleBasedSegmentProcessor {
private static final Logger _log = LoggerFactory.getLogger(RuleBasedSegmentProcessor.class);

public static RuleBasedSegmentsToUpdate processRuleBasedSegmentChanges(RuleBasedSegmentParser ruleBasedSegmentParser,
List<RuleBasedSegment> ruleBasedSegments) {
List<ParsedRuleBasedSegment> toAdd = new ArrayList<>();
List<String> toRemove = new ArrayList<>();
Set<String> segments = new HashSet<>();
for (RuleBasedSegment ruleBasedSegment : ruleBasedSegments) {
if (ruleBasedSegment.status != Status.ACTIVE) {
// archive.
toRemove.add(ruleBasedSegment.name);
continue;
}
ParsedRuleBasedSegment parsedRuleBasedSegment = ruleBasedSegmentParser.parse(ruleBasedSegment);
if (parsedRuleBasedSegment == null) {
_log.debug(String.format("We could not parse the rule based segment definition for: %s", ruleBasedSegment.name));
continue;
}
segments.addAll(parsedRuleBasedSegment.getSegmentsNames());
toAdd.add(parsedRuleBasedSegment);
}
return new RuleBasedSegmentsToUpdate(toAdd, toRemove, segments);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.split.client.utils;

import io.split.engine.experiments.ParsedRuleBasedSegment;
import io.split.engine.experiments.ParsedSplit;

import java.util.List;
import java.util.Set;

public class RuleBasedSegmentsToUpdate {
List<ParsedRuleBasedSegment> toAdd;
List<String> toRemove;
Set<String> segments;

public RuleBasedSegmentsToUpdate(List<ParsedRuleBasedSegment> toAdd, List<String> toRemove, Set<String> segments) {
this.toAdd = toAdd;
this.toRemove = toRemove;
this.segments = segments;
}

public List<ParsedRuleBasedSegment> getToAdd() {
return toAdd;
}

public List<String> getToRemove() {
return toRemove;
}

public Set<String> getSegments() {
return segments;
}
}
Loading