Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions .github/linter/checkstyle-suppressions.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0"?>

<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">

<suppressions>
<suppress checks="LineLength" files=".*(test|it)[\\/]"/>
</suppressions>
380 changes: 380 additions & 0 deletions .github/linter/google-java-style.xml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ jobs:
if: matrix.jdk == '8' && github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development'
run: mvn --batch-mode clean install

- name: Linter
if: matrix.jdk == '8' && github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development'
run: mvn checkstyle::check

- name: Deploy
if: matrix.jdk == '8' && github.event_name == 'push' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development'
run: mvn --batch-mode deploy -P test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public final class HttpSegmentChangeFetcher implements SegmentChangeFetcher {
private final URI _target;
private final TelemetryRuntimeProducer _telemetryRuntimeProducer;

public static HttpSegmentChangeFetcher create(CloseableHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer) throws URISyntaxException {
public static HttpSegmentChangeFetcher create(CloseableHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer)
throws URISyntaxException {
return new HttpSegmentChangeFetcher(client, Utils.appendPath(root, "api/segmentChanges"), telemetryRuntimeProducer);
}

Expand Down Expand Up @@ -102,7 +103,8 @@ public SegmentChange fetch(String segmentName, long since, FetchOptions options)
_log.error("factory instantiation: you passed a client side type sdkKey, " +
"please grab an sdk key from the Split user interface that is of type server side");
}
throw new IllegalStateException(String.format("Could not retrieve segment changes for %s, since %s; http return code %s", segmentName, since, statusCode));
throw new IllegalStateException(String.format("Could not retrieve segment changes for %s, since %s; http return code %s",
segmentName, since, statusCode));
}

_telemetryRuntimeProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.SEGMENTS, System.currentTimeMillis());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public final class HttpSplitChangeFetcher implements SplitChangeFetcher {
private final URI _target;
private final TelemetryRuntimeProducer _telemetryRuntimeProducer;

public static HttpSplitChangeFetcher create(CloseableHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer) throws URISyntaxException {
public static HttpSplitChangeFetcher create(CloseableHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer)
throws URISyntaxException {
return new HttpSplitChangeFetcher(client, Utils.appendPath(root, "api/splitChanges"), telemetryRuntimeProducer);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public SplitChange fetch(long since, FetchOptions options) {
_log.warn(String.format("There was no file named %s found. " +
"We created a split client that returns default treatments for all feature flags for all of your users. " +
"If you wish to return a specific treatment for a feature flag, enter the name of that feature flag name and " +
"treatment name separated by whitespace in %s; one pair per line. Empty lines or lines starting with '#' are considered comments",
"treatment name separated by whitespace in %s; one pair per line. Empty lines or lines starting with '#' are " +
"considered comments",
_file.getPath(), _file.getPath()), f);
throw new IllegalStateException("Problem fetching splitChanges: " + f.getMessage(), f);
} catch (Exception e) {
Expand Down
4 changes: 2 additions & 2 deletions client/src/main/java/io/split/client/SplitClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ public interface SplitClient {
*
* @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null.
* @param featureFlagNames the names of the feature flags we want to evaluate. MUST NOT be null.
* @return Map<String, SplitResult> containing for each feature flag the evaluated treatment (the default treatment of this feature flag, or 'control') and
* a configuration associated to this treatment if set.
* @return Map<String, SplitResult> containing for each feature flag the evaluated treatment (the default treatment of
* this feature flag, or 'control') and a configuration associated to this treatment if set.
*/
Map<String, SplitResult> getTreatmentsWithConfig(String key, List<String> featureFlagNames);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ public static final class Builder {
private String _authServiceURL = AUTH_ENDPOINT;
private String _streamingServiceURL = STREAMING_ENDPOINT;
private String _telemetryURl = TELEMETRY_ENDPOINT;
private int _telemetryRefreshRate = 3600;
private int _telemetryRefreshRate = 600;
private final int _uniqueKeysRefreshRateInMemory = 900;
private final int _uniqueKeysRefreshRateRedis = 300;
private final int _filterUniqueKeysRefreshRate = 86400;
Expand Down
32 changes: 20 additions & 12 deletions client/src/main/java/io/split/client/SplitClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ public Map<String, String> getTreatments(Key key, List<String> featureFlagNames,

@Override
public Map<String, SplitResult> getTreatmentsWithConfig(String key, List<String> featureFlagNames) {
return getTreatmentsWithConfigInternal(key, null, featureFlagNames, Collections.<String, Object>emptyMap(), MethodEnum.TREATMENTS_WITH_CONFIG);
return getTreatmentsWithConfigInternal(key, null, featureFlagNames, Collections.<String, Object>emptyMap(),
MethodEnum.TREATMENTS_WITH_CONFIG);
}

@Override
Expand All @@ -135,7 +136,8 @@ public Map<String, SplitResult> getTreatmentsWithConfig(String key, List<String>

@Override
public Map<String, SplitResult> getTreatmentsWithConfig(Key key, List<String> featureFlagNames, Map<String, Object> attributes) {
return getTreatmentsWithConfigInternal(key.matchingKey(), key.bucketingKey(), featureFlagNames, attributes, MethodEnum.TREATMENTS_WITH_CONFIG);
return getTreatmentsWithConfigInternal(key.matchingKey(), key.bucketingKey(), featureFlagNames, attributes,
MethodEnum.TREATMENTS_WITH_CONFIG);
}

@Override
Expand Down Expand Up @@ -220,7 +222,8 @@ private boolean track(Event event) {
return _eventsStorageProducer.track(event, propertiesResult.getEventSize());
}

private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bucketingKey, String featureFlag, Map<String, Object> attributes, MethodEnum methodEnum) {
private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bucketingKey, String featureFlag, Map<String,
Object> attributes, MethodEnum methodEnum) {
long initTime = System.currentTimeMillis();
try {
checkSDKReady(methodEnum);
Expand Down Expand Up @@ -279,7 +282,8 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu
}
}

private Map<String, SplitResult> getTreatmentsWithConfigInternal(String matchingKey, String bucketingKey, List<String> featureFlagNames, Map<String, Object> attributes, MethodEnum methodEnum) {
private Map<String, SplitResult> getTreatmentsWithConfigInternal(String matchingKey, String bucketingKey, List<String> featureFlagNames,
Map<String, Object> attributes, MethodEnum methodEnum) {
long initTime = System.currentTimeMillis();
if (featureFlagNames == null) {
_log.error(String.format("%s: featureFlagNames must be a non-empty array", methodEnum.getMethod()));
Expand All @@ -303,17 +307,20 @@ private Map<String, SplitResult> getTreatmentsWithConfigInternal(String matching
return new HashMap<>();
}
featureFlagNames = SplitNameValidator.areValid(featureFlagNames, methodEnum.getMethod());
Map<String, EvaluatorImp.TreatmentLabelAndChangeNumber> evaluatorResult = _evaluator.evaluateFeatures(matchingKey, bucketingKey, featureFlagNames, attributes);
Map<String, EvaluatorImp.TreatmentLabelAndChangeNumber> evaluatorResult = _evaluator.evaluateFeatures(matchingKey,
bucketingKey, featureFlagNames, attributes);
List<Impression> impressions = new ArrayList<>();
Map<String, SplitResult> result = new HashMap<>();
evaluatorResult.keySet().forEach(t -> {
if (evaluatorResult.get(t).treatment.equals(Treatments.CONTROL) && evaluatorResult.get(t).label.equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
_log.warn(String.format(
"%s: you passed \"%s\" that does not exist in this environment please double check what feature flags exist in the Split user interface.", methodEnum.getMethod(), t));
if (evaluatorResult.get(t).treatment.equals(Treatments.CONTROL) && evaluatorResult.get(t).label.
equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
_log.warn(String.format("%s: you passed \"%s\" that does not exist in this environment please double check " +
"what feature flags exist in the Split user interface.", methodEnum.getMethod(), t));
result.put(t, SPLIT_RESULT_CONTROL);
} else {
result.put(t, new SplitResult(evaluatorResult.get(t).treatment, evaluatorResult.get(t).configurations));
impressions.add(new Impression(matchingKey, bucketingKey, t, evaluatorResult.get(t).treatment, System.currentTimeMillis(), evaluatorResult.get(t).label, evaluatorResult.get(t).changeNumber, attributes));
impressions.add(new Impression(matchingKey, bucketingKey, t, evaluatorResult.get(t).treatment, System.currentTimeMillis(),
evaluatorResult.get(t).label, evaluatorResult.get(t).changeNumber, attributes));
}
});

Expand All @@ -337,7 +344,8 @@ private Map<String, SplitResult> getTreatmentsWithConfigInternal(String matching
private void recordStats(String matchingKey, String bucketingKey, String featureFlagName, long start, String result,
String operation, String label, Long changeNumber, Map<String, Object> attributes) {
try {
_impressionManager.track(Stream.of(new Impression(matchingKey, bucketingKey, featureFlagName, result, System.currentTimeMillis(), label, changeNumber, attributes)).collect(Collectors.toList()));
_impressionManager.track(Stream.of(new Impression(matchingKey, bucketingKey, featureFlagName, result, System.currentTimeMillis(),
label, changeNumber, attributes)).collect(Collectors.toList()));
} catch (Throwable t) {
_log.error("Exception", t);
}
Expand All @@ -354,8 +362,8 @@ private Event createEvent(String key, String trafficType, String eventType) {

private void checkSDKReady(MethodEnum methodEnum) {
if (!_gates.isSDKReady()) {
_log.warn(String.format(
"%s: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method", methodEnum.getMethod()));
_log.warn(String.format("%s: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness " +
"before using this method", methodEnum.getMethod()));
_telemetryConfigProducer.recordNonReadyUsage();
}
}
Expand Down
27 changes: 18 additions & 9 deletions client/src/main/java/io/split/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
ImpressionsStorage impressionsStorage = new InMemoryImpressionsStorage(config.impressionsQueueSize());
_splitCache = splitCache;
_segmentCache = segmentCache;
_telemetrySynchronizer = new TelemetryInMemorySubmitter(_httpclient, URI.create(config.telemetryURL()), telemetryStorage, splitCache, _segmentCache, telemetryStorage, _startTime);
_telemetrySynchronizer = new TelemetryInMemorySubmitter(_httpclient, URI.create(config.telemetryURL()), telemetryStorage,
splitCache, _segmentCache, telemetryStorage, _startTime);

// Segments
_segmentSynchronizationTaskImp = buildSegments(config, segmentCache, splitCache);
Expand All @@ -200,7 +201,8 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
config.getThreadFactory());

//ImpressionSender
_impressionsSender = HttpImpressionsSender.create(_httpclient, URI.create(config.eventsEndpoint()), config.impressionsMode(), _telemetryStorageProducer);
_impressionsSender = HttpImpressionsSender.create(_httpclient, URI.create(config.eventsEndpoint()), config.impressionsMode(),
_telemetryStorageProducer);

//UniqueKeysTracker
_uniqueKeysTracker = createUniqueKeysTracker(config);
Expand Down Expand Up @@ -267,8 +269,10 @@ protected SplitFactoryImpl(String apiToken, SplitClientConfig config, CustomStor
_userStorageWrapper = new UserStorageWrapper(customStorageWrapper);
UserCustomSegmentAdapterConsumer userCustomSegmentAdapterConsumer= new UserCustomSegmentAdapterConsumer(customStorageWrapper);
UserCustomSplitAdapterConsumer userCustomSplitAdapterConsumer = new UserCustomSplitAdapterConsumer(customStorageWrapper);
UserCustomImpressionAdapterConsumer userCustomImpressionAdapterConsumer = new UserCustomImpressionAdapterConsumer(); // TODO migrate impressions sender to Task instead manager and not instantiate Producer here.
UserCustomImpressionAdapterProducer userCustomImpressionAdapterProducer = new UserCustomImpressionAdapterProducer(customStorageWrapper, metadata);
// TODO migrate impressions sender to Task instead manager and not instantiate Producer here.
UserCustomImpressionAdapterConsumer userCustomImpressionAdapterConsumer = new UserCustomImpressionAdapterConsumer();
UserCustomImpressionAdapterProducer userCustomImpressionAdapterProducer = new UserCustomImpressionAdapterProducer(customStorageWrapper,
metadata);
UserCustomEventAdapterProducer userCustomEventAdapterProducer = new UserCustomEventAdapterProducer(customStorageWrapper, metadata);

_operationMode = config.operationMode();
Expand Down Expand Up @@ -543,7 +547,8 @@ private static HttpClientBuilder setupProxy(HttpClientBuilder httpClientbuilder,
return httpClientbuilder;
}

private SegmentSynchronizationTaskImp buildSegments(SplitClientConfig config, SegmentCacheProducer segmentCacheProducer, SplitCacheConsumer splitCacheConsumer) throws URISyntaxException {
private SegmentSynchronizationTaskImp buildSegments(SplitClientConfig config, SegmentCacheProducer segmentCacheProducer,
SplitCacheConsumer splitCacheConsumer) throws URISyntaxException {
SegmentChangeFetcher segmentChangeFetcher = HttpSegmentChangeFetcher.create(_httpclient, _rootTarget, _telemetryStorageProducer);

return new SegmentSynchronizationTaskImp(segmentChangeFetcher,
Expand All @@ -561,7 +566,8 @@ private SplitFetcher buildSplitFetcher(SplitCacheProducer splitCacheProducer, Sp
return new SplitFetcherImp(splitChangeFetcher, splitParser, splitCacheProducer, _telemetryStorageProducer);
}

private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config, ImpressionsStorageConsumer impressionsStorageConsumer, ImpressionsStorageProducer impressionsStorageProducer) throws URISyntaxException {
private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config, ImpressionsStorageConsumer impressionsStorageConsumer,
ImpressionsStorageProducer impressionsStorageProducer) throws URISyntaxException {
List<ImpressionListener> impressionListeners = new ArrayList<>();
if (config.integrationsConfig() != null) {
config.integrationsConfig().getImpressionsListeners(IntegrationsConfig.Execution.ASYNC).stream()
Expand Down Expand Up @@ -591,7 +597,8 @@ private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config,
processImpressionStrategy = new ProcessImpressionNone(listener != null, _uniqueKeysTracker, counter);
break;
}
return ImpressionsManagerImpl.instance(config, _telemetryStorageProducer, impressionsStorageConsumer, impressionsStorageProducer, _impressionsSender, processImpressionStrategy, counter, listener);
return ImpressionsManagerImpl.instance(config, _telemetryStorageProducer, impressionsStorageConsumer, impressionsStorageProducer,
_impressionsSender, processImpressionStrategy, counter, listener);
}

private SDKMetadata createSdkMetadata(boolean ipAddressEnabled, String splitSdkVersion) {
Expand Down Expand Up @@ -622,15 +629,17 @@ private void manageSdkReady(SplitClientConfig config) {
}
}
_gates.sdkInternalReady();
_telemetrySynchronizer.synchronizeConfig(config, System.currentTimeMillis(), ApiKeyCounter.getApiKeyCounterInstance().getFactoryInstances(), new ArrayList<>());
_telemetrySynchronizer.synchronizeConfig(config, System.currentTimeMillis(), ApiKeyCounter.getApiKeyCounterInstance().
getFactoryInstances(), new ArrayList<>());
});
}

private UniqueKeysTracker createUniqueKeysTracker(SplitClientConfig config){
if (config.impressionsMode().equals(ImpressionsManager.Mode.NONE)){
int uniqueKeysRefreshRate = config.operationMode().equals(OperationMode.STANDALONE) ? config.uniqueKeysRefreshRateInMemory()
: config.uniqueKeysRefreshRateRedis();
return new UniqueKeysTrackerImp(_telemetrySynchronizer, uniqueKeysRefreshRate, config.filterUniqueKeysRefreshRate(), config.getThreadFactory());
return new UniqueKeysTrackerImp(_telemetrySynchronizer, uniqueKeysRefreshRate, config.filterUniqueKeysRefreshRate(),
config.getThreadFactory());
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ public SplitChange fetch(long since, FetchOptions options) {
splitChange.since = since;
return splitChange;
} catch (FileNotFoundException f) {
_log.warn(String.format("There was no file named %s found. " +
"We created a split client that returns default treatments for all feature flags for all of your users. " +
"If you wish to return a specific treatment for a feature flag, enter the name of that feature flag name and " +
"treatment name separated by whitespace in %s; one pair per line. Empty lines or lines starting with '#' are considered comments",
_log.warn(String.format("There was no file named %s found. We created a split client that returns default treatments " +
"for all feature flags for all of your users. If you wish to return a specific treatment for a feature flag, " +
"enter the name of that feature flag name and treatment name separated by whitespace in %s; one pair per line. " +
"Empty lines or lines starting with '#' are considered comments",
_splitFile.getPath(), _splitFile.getPath()), f);
throw new IllegalStateException("Problem fetching splitChanges: " + f.getMessage(), f);
} catch (Exception e) {
Expand Down
Loading