Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release version 4.13.0 #516

Merged
merged 45 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fa8de3f
added kerberos auth support
Aug 13, 2024
2234a3c
polish
Aug 13, 2024
aa40aca
polish
Aug 13, 2024
c1933cb
polish
Aug 13, 2024
077accd
added enum for AuthScheme
Aug 13, 2024
4a7079a
polish
Aug 14, 2024
2ec4789
polish
Aug 14, 2024
97bf31b
updated version
Aug 14, 2024
e388362
Merge pull request #511 from splitio/kerberos-support
chillaq Aug 14, 2024
acee253
Changed Kerberos client to use okhttp lib
Aug 21, 2024
87f5586
Added tests
Aug 29, 2024
fe52d1c
added kerberos client test in factory
Aug 30, 2024
f0e9d22
fix tests
Aug 30, 2024
a96c19e
fix tests
Aug 30, 2024
26389a7
polish
Aug 30, 2024
03e2750
polish
Aug 30, 2024
bf9f600
added KerberosAuth test
Sep 4, 2024
739a9ac
added kerberos config
Sep 5, 2024
eb98607
added more coverage for kerberos http client
Sep 5, 2024
32adc6d
added coverage for kerberos in factory class
Sep 5, 2024
e4b407d
more kerberos test
Sep 5, 2024
182044b
revert delay to 2 seconds in test
Sep 5, 2024
da16ffb
increased timeout
Sep 5, 2024
354c345
revert timeout to 2s
Sep 5, 2024
f1c8a7f
added multiple sleep calls
Sep 5, 2024
bcd9ac8
tyring to work around sleep code smell
Sep 5, 2024
62d8e43
revert back to 2s sleep
Sep 5, 2024
ff585aa
polish
Sep 5, 2024
00a9c0c
using proxy prefix for kerberos config param
Sep 6, 2024
7d136d7
allow release of all SDK modules
Sep 6, 2024
9e46ad5
Refactor kerberos code to sub module
Sep 10, 2024
1e9482d
refactor to http-modules
Sep 10, 2024
bb87766
separated httpclient from module
Sep 11, 2024
4d888cb
renamed module to okhttp-modules
Sep 11, 2024
cfdc429
Merge pull request #513 from splitio/kerberos-module-refactor
chillaq Sep 11, 2024
aac8a1b
added tests for httpmodule
Sep 11, 2024
3c853dc
remove apache from module api
mredolatti Sep 12, 2024
a50d79a
fixed post body in okhttp
Sep 12, 2024
2299e38
Merge pull request #515 from splitio/remove_apache_from_api
chillaq Sep 12, 2024
fa2b6a7
re-add request decorator
mredolatti Sep 12, 2024
568b511
- fixed SSE NPE with request decorator
Sep 12, 2024
84eeea5
fixed okhttp decorator errors and updated tests
Sep 13, 2024
24852ea
fixed checking headers in decorator and updated tests
Sep 13, 2024
d484a21
polishing
Sep 13, 2024
54fd41c
Merge pull request #512 from splitio/kerberos-okhttp
chillaq Sep 13, 2024
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
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
Loading