Skip to content

Commit

Permalink
Merge pull request #516 from splitio/development
Browse files Browse the repository at this point in the history
Release version 4.13.0
  • Loading branch information
chillaq authored Sep 13, 2024
2 parents 50dc950 + 54fd41c commit 11ed5df
Show file tree
Hide file tree
Showing 39 changed files with 2,038 additions and 184 deletions.
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
4.13.0 (Sep 13, 2024)
- Added support for Kerberos Proxy authentication.

4.12.1 (Jun 10, 2024)
- Fixed deadlock for virtual thread in Push Manager and SSE Client.

Expand Down
15 changes: 14 additions & 1 deletion client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>io.split.client</groupId>
<artifactId>java-client-parent</artifactId>
<version>4.12.1</version>
<version>4.13.0</version>
</parent>
<artifactId>java-client</artifactId>
<packaging>jar</packaging>
Expand Down Expand Up @@ -64,6 +64,7 @@
<include>io.split.schemas:*</include>
<include>io.codigo.grammar:*</include>
<include>org.apache.httpcomponents.*</include>
<include>org.apache.hc.*</include>
<include>com.google.*</include>
<include>org.yaml:snakeyaml:*</include>

Expand Down Expand Up @@ -238,5 +239,17 @@
<version>4.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
44 changes: 7 additions & 37 deletions client/src/main/java/io/split/client/RequestDecorator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@

import io.split.client.dtos.RequestContext;

import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.Header;

import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Set;
import java.util.List;
import java.util.stream.Collectors;

public final class RequestDecorator {
CustomHeaderDecorator _headerDecorator;
Expand All @@ -36,42 +32,16 @@ public RequestDecorator(CustomHeaderDecorator headerDecorator) {
: headerDecorator;
}

public HttpRequest decorateHeaders(HttpRequest request) {
public RequestContext decorateHeaders(RequestContext request) {
try {
Map<String, List<String>> headers = _headerDecorator
.getHeaderOverrides(new RequestContext(convertToMap(request.getHeaders())));
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
if (isHeaderAllowed(entry.getKey())) {
List<String> values = entry.getValue();
for (int i = 0; i < values.size(); i++) {
if (i == 0) {
request.setHeader(entry.getKey(), values.get(i));
} else {
request.addHeader(entry.getKey(), values.get(i));
}
}
}
}
return new RequestContext(_headerDecorator.getHeaderOverrides(request)
.entrySet()
.stream()
.filter(e -> !forbiddenHeaders.contains(e.getKey().toLowerCase()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
} catch (Exception e) {
throw new IllegalArgumentException(
String.format("Problem adding custom headers to request decorator: %s", e), e);
}

return request;
}

private boolean isHeaderAllowed(String headerName) {
return !forbiddenHeaders.contains(headerName.toLowerCase());
}

private Map<String, List<String>> convertToMap(Header[] to_convert) {
Map<String, List<String>> to_return = new HashMap<String, List<String>>();
for (Integer i = 0; i < to_convert.length; i++) {
if (!to_return.containsKey(to_convert[i].getName())) {
to_return.put(to_convert[i].getName(), new ArrayList<String>());
}
to_return.get(to_convert[i].getName()).add(to_convert[i].getValue());
}
return to_return;
}
}
133 changes: 87 additions & 46 deletions client/src/main/java/io/split/client/SplitClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.split.client.impressions.ImpressionsManager;
import io.split.client.utils.FileTypeEnum;
import io.split.integrations.IntegrationsConfig;
import io.split.service.CustomHttpModule;
import io.split.storages.enums.OperationMode;
import io.split.storages.enums.StorageMode;
import org.apache.hc.core5.http.HttpHost;
Expand Down Expand Up @@ -91,7 +92,7 @@ public class SplitClientConfig {
private final HashSet<String> _flagSetsFilter;
private final int _invalidSets;
private final CustomHeaderDecorator _customHeaderDecorator;

private final CustomHttpModule _alternativeHTTPModule;

public static Builder builder() {
return new Builder();
Expand Down Expand Up @@ -148,7 +149,8 @@ private SplitClientConfig(String endpoint,
ThreadFactory threadFactory,
HashSet<String> flagSetsFilter,
int invalidSets,
CustomHeaderDecorator customHeaderDecorator) {
CustomHeaderDecorator customHeaderDecorator,
CustomHttpModule alternativeHTTPModule) {
_endpoint = endpoint;
_eventsEndpoint = eventsEndpoint;
_featuresRefreshRate = pollForFeatureChangesEveryNSeconds;
Expand Down Expand Up @@ -201,6 +203,7 @@ private SplitClientConfig(String endpoint,
_flagSetsFilter = flagSetsFilter;
_invalidSets = invalidSets;
_customHeaderDecorator = customHeaderDecorator;
_alternativeHTTPModule = alternativeHTTPModule;

Properties props = new Properties();
try {
Expand Down Expand Up @@ -409,6 +412,7 @@ public CustomHeaderDecorator customHeaderDecorator() {
return _customHeaderDecorator;
}

public CustomHttpModule alternativeHTTPModule() { return _alternativeHTTPModule; }
public static final class Builder {

private String _endpoint = SDK_ENDPOINT;
Expand Down Expand Up @@ -466,6 +470,7 @@ public static final class Builder {
private HashSet<String> _flagSetsFilter = new HashSet<>();
private int _invalidSetsCount = 0;
private CustomHeaderDecorator _customHeaderDecorator = null;
private CustomHttpModule _alternativeHTTPModule = null;

public Builder() {
}
Expand Down Expand Up @@ -960,6 +965,17 @@ public Builder customHeaderDecorator(CustomHeaderDecorator customHeaderDecorator
return this;
}

/**
* Alternative Http Client
*
* @param alternativeHTTPModule
* @return this builder
*/
public Builder alternativeHTTPModule(CustomHttpModule alternativeHTTPModule) {
_alternativeHTTPModule = alternativeHTTPModule;
return this;
}

/**
* Thread Factory
*
Expand All @@ -971,7 +987,7 @@ public Builder threadFactory(ThreadFactory threadFactory) {
return this;
}

public SplitClientConfig build() {
private void verifyRates() {
if (_featuresRefreshRate < 5 ) {
throw new IllegalArgumentException("featuresRefreshRate must be >= 5: " + _featuresRefreshRate);
}
Expand All @@ -980,35 +996,19 @@ public SplitClientConfig build() {
throw new IllegalArgumentException("segmentsRefreshRate must be >= 30: " + _segmentsRefreshRate);
}

switch (_impressionsMode) {
case OPTIMIZED:
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 300 : Math.max(60, _impressionsRefreshRate);
break;
case DEBUG:
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 60 : _impressionsRefreshRate;
break;
}

if (_eventSendIntervalInMillis < 1000) {
throw new IllegalArgumentException("_eventSendIntervalInMillis must be >= 1000: " + _eventSendIntervalInMillis);
}

if (_metricsRefreshRate < 30) {
throw new IllegalArgumentException("metricsRefreshRate must be >= 30: " + _metricsRefreshRate);
}

if (_impressionsQueueSize <=0 ) {
throw new IllegalArgumentException("impressionsQueueSize must be > 0: " + _impressionsQueueSize);
}

if (_connectionTimeout <= 0) {
throw new IllegalArgumentException("connectionTimeOutInMs must be > 0: " + _connectionTimeout);
}

if (_readTimeout <= 0) {
throw new IllegalArgumentException("readTimeout must be > 0: " + _readTimeout);
if(_telemetryRefreshRate < 60) {
throw new IllegalStateException("_telemetryRefreshRate must be >= 60");
}
}

private void verifyEndPoints() {
if (_endpoint == null) {
throw new IllegalArgumentException("endpoint must not be null");
}
Expand All @@ -1021,18 +1021,6 @@ public SplitClientConfig build() {
throw new IllegalArgumentException("If endpoint is set, you must also set the events endpoint");
}

if (_numThreadsForSegmentFetch <= 0) {
throw new IllegalArgumentException("Number of threads for fetching segments MUST be greater than zero");
}

if (_authRetryBackoffBase <= 0) {
throw new IllegalArgumentException("authRetryBackoffBase: must be >= 1");
}

if (_streamingReconnectBackoffBase <= 0) {
throw new IllegalArgumentException("streamingReconnectBackoffBase: must be >= 1");
}

if (_authServiceURL == null) {
throw new IllegalArgumentException("authServiceURL must not be null");
}
Expand All @@ -1044,31 +1032,83 @@ public SplitClientConfig build() {
if (_telemetryURl == null) {
throw new IllegalArgumentException("telemetryURl must not be null");
}
}

if (_onDemandFetchRetryDelayMs <= 0) {
throw new IllegalStateException("streamingRetryDelay must be > 0");
private void verifyAllModes() {
switch (_impressionsMode) {
case OPTIMIZED:
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 300 : Math.max(60, _impressionsRefreshRate);
break;
case DEBUG:
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 60 : _impressionsRefreshRate;
break;
case NONE:
break;
}

if(_onDemandFetchMaxRetries <= 0) {
throw new IllegalStateException("_onDemandFetchMaxRetries must be > 0");
if (_impressionsQueueSize <=0 ) {
throw new IllegalArgumentException("impressionsQueueSize must be > 0: " + _impressionsQueueSize);
}

if(_storageMode == null) {
_storageMode = StorageMode.MEMORY;
}

if(_telemetryRefreshRate < 60) {
throw new IllegalStateException("_telemetryRefreshRate must be >= 60");
}

if(OperationMode.CONSUMER.equals(_operationMode)){
if(_customStorageWrapper == null) {
throw new IllegalStateException("Custom Storage must not be null on Consumer mode.");
}
_storageMode = StorageMode.PLUGGABLE;
}
}

private void verifyNetworkParams() {
if (_connectionTimeout <= 0) {
throw new IllegalArgumentException("connectionTimeOutInMs must be > 0: " + _connectionTimeout);
}

if (_readTimeout <= 0) {
throw new IllegalArgumentException("readTimeout must be > 0: " + _readTimeout);
}
if (_authRetryBackoffBase <= 0) {
throw new IllegalArgumentException("authRetryBackoffBase: must be >= 1");
}

if (_streamingReconnectBackoffBase <= 0) {
throw new IllegalArgumentException("streamingReconnectBackoffBase: must be >= 1");
}

if (_onDemandFetchRetryDelayMs <= 0) {
throw new IllegalStateException("streamingRetryDelay must be > 0");
}

if(_onDemandFetchMaxRetries <= 0) {
throw new IllegalStateException("_onDemandFetchMaxRetries must be > 0");
}
}

private void verifyAlternativeClient() {
if (_alternativeHTTPModule != null && _streamingEnabled) {
throw new IllegalArgumentException("Streaming feature is not supported with Alternative HTTP Client");
}
}

public SplitClientConfig build() {

verifyRates();

verifyAllModes();

verifyEndPoints();

verifyNetworkParams();

verifyAlternativeClient();

if (_numThreadsForSegmentFetch <= 0) {
throw new IllegalArgumentException("Number of threads for fetching segments MUST be greater than zero");
}

return new SplitClientConfig(
return new SplitClientConfig(
_endpoint,
_eventsEndpoint,
_featuresRefreshRate,
Expand Down Expand Up @@ -1120,7 +1160,8 @@ public SplitClientConfig build() {
_threadFactory,
_flagSetsFilter,
_invalidSetsCount,
_customHeaderDecorator);
_customHeaderDecorator,
_alternativeHTTPModule);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.split.inputValidation.ApiKeyValidator;
import io.split.grammar.Treatments;
import io.split.service.SplitHttpClient;
import io.split.storages.enums.StorageMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down
Loading

0 comments on commit 11ed5df

Please sign in to comment.