Skip to content

Commit 11ed5df

Browse files
authored
Merge pull request #516 from splitio/development
Release version 4.13.0
2 parents 50dc950 + 54fd41c commit 11ed5df

39 files changed

+2038
-184
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
4.13.0 (Sep 13, 2024)
2+
- Added support for Kerberos Proxy authentication.
3+
14
4.12.1 (Jun 10, 2024)
25
- Fixed deadlock for virtual thread in Push Manager and SSE Client.
36

client/pom.xml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>io.split.client</groupId>
77
<artifactId>java-client-parent</artifactId>
8-
<version>4.12.1</version>
8+
<version>4.13.0</version>
99
</parent>
1010
<artifactId>java-client</artifactId>
1111
<packaging>jar</packaging>
@@ -64,6 +64,7 @@
6464
<include>io.split.schemas:*</include>
6565
<include>io.codigo.grammar:*</include>
6666
<include>org.apache.httpcomponents.*</include>
67+
<include>org.apache.hc.*</include>
6768
<include>com.google.*</include>
6869
<include>org.yaml:snakeyaml:*</include>
6970

@@ -238,5 +239,17 @@
238239
<version>4.0.3</version>
239240
<scope>test</scope>
240241
</dependency>
242+
<dependency>
243+
<groupId>org.powermock</groupId>
244+
<artifactId>powermock-module-junit4</artifactId>
245+
<version>1.7.4</version>
246+
<scope>test</scope>
247+
</dependency>
248+
<dependency>
249+
<groupId>org.powermock</groupId>
250+
<artifactId>powermock-api-mockito</artifactId>
251+
<version>1.7.4</version>
252+
<scope>test</scope>
253+
</dependency>
241254
</dependencies>
242255
</project>

client/src/main/java/io/split/client/RequestDecorator.java

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22

33
import io.split.client.dtos.RequestContext;
44

5-
import org.apache.hc.core5.http.HttpRequest;
6-
import org.apache.hc.core5.http.Header;
75

86
import java.util.HashSet;
9-
import java.util.HashMap;
107
import java.util.Map;
118
import java.util.Arrays;
12-
import java.util.ArrayList;
139
import java.util.Set;
14-
import java.util.List;
10+
import java.util.stream.Collectors;
1511

1612
public final class RequestDecorator {
1713
CustomHeaderDecorator _headerDecorator;
@@ -36,42 +32,16 @@ public RequestDecorator(CustomHeaderDecorator headerDecorator) {
3632
: headerDecorator;
3733
}
3834

39-
public HttpRequest decorateHeaders(HttpRequest request) {
35+
public RequestContext decorateHeaders(RequestContext request) {
4036
try {
41-
Map<String, List<String>> headers = _headerDecorator
42-
.getHeaderOverrides(new RequestContext(convertToMap(request.getHeaders())));
43-
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
44-
if (isHeaderAllowed(entry.getKey())) {
45-
List<String> values = entry.getValue();
46-
for (int i = 0; i < values.size(); i++) {
47-
if (i == 0) {
48-
request.setHeader(entry.getKey(), values.get(i));
49-
} else {
50-
request.addHeader(entry.getKey(), values.get(i));
51-
}
52-
}
53-
}
54-
}
37+
return new RequestContext(_headerDecorator.getHeaderOverrides(request)
38+
.entrySet()
39+
.stream()
40+
.filter(e -> !forbiddenHeaders.contains(e.getKey().toLowerCase()))
41+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
5542
} catch (Exception e) {
5643
throw new IllegalArgumentException(
5744
String.format("Problem adding custom headers to request decorator: %s", e), e);
5845
}
59-
60-
return request;
61-
}
62-
63-
private boolean isHeaderAllowed(String headerName) {
64-
return !forbiddenHeaders.contains(headerName.toLowerCase());
65-
}
66-
67-
private Map<String, List<String>> convertToMap(Header[] to_convert) {
68-
Map<String, List<String>> to_return = new HashMap<String, List<String>>();
69-
for (Integer i = 0; i < to_convert.length; i++) {
70-
if (!to_return.containsKey(to_convert[i].getName())) {
71-
to_return.put(to_convert[i].getName(), new ArrayList<String>());
72-
}
73-
to_return.get(to_convert[i].getName()).add(to_convert[i].getValue());
74-
}
75-
return to_return;
7646
}
7747
}

client/src/main/java/io/split/client/SplitClientConfig.java

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.split.client.impressions.ImpressionsManager;
55
import io.split.client.utils.FileTypeEnum;
66
import io.split.integrations.IntegrationsConfig;
7+
import io.split.service.CustomHttpModule;
78
import io.split.storages.enums.OperationMode;
89
import io.split.storages.enums.StorageMode;
910
import org.apache.hc.core5.http.HttpHost;
@@ -91,7 +92,7 @@ public class SplitClientConfig {
9192
private final HashSet<String> _flagSetsFilter;
9293
private final int _invalidSets;
9394
private final CustomHeaderDecorator _customHeaderDecorator;
94-
95+
private final CustomHttpModule _alternativeHTTPModule;
9596

9697
public static Builder builder() {
9798
return new Builder();
@@ -148,7 +149,8 @@ private SplitClientConfig(String endpoint,
148149
ThreadFactory threadFactory,
149150
HashSet<String> flagSetsFilter,
150151
int invalidSets,
151-
CustomHeaderDecorator customHeaderDecorator) {
152+
CustomHeaderDecorator customHeaderDecorator,
153+
CustomHttpModule alternativeHTTPModule) {
152154
_endpoint = endpoint;
153155
_eventsEndpoint = eventsEndpoint;
154156
_featuresRefreshRate = pollForFeatureChangesEveryNSeconds;
@@ -201,6 +203,7 @@ private SplitClientConfig(String endpoint,
201203
_flagSetsFilter = flagSetsFilter;
202204
_invalidSets = invalidSets;
203205
_customHeaderDecorator = customHeaderDecorator;
206+
_alternativeHTTPModule = alternativeHTTPModule;
204207

205208
Properties props = new Properties();
206209
try {
@@ -409,6 +412,7 @@ public CustomHeaderDecorator customHeaderDecorator() {
409412
return _customHeaderDecorator;
410413
}
411414

415+
public CustomHttpModule alternativeHTTPModule() { return _alternativeHTTPModule; }
412416
public static final class Builder {
413417

414418
private String _endpoint = SDK_ENDPOINT;
@@ -466,6 +470,7 @@ public static final class Builder {
466470
private HashSet<String> _flagSetsFilter = new HashSet<>();
467471
private int _invalidSetsCount = 0;
468472
private CustomHeaderDecorator _customHeaderDecorator = null;
473+
private CustomHttpModule _alternativeHTTPModule = null;
469474

470475
public Builder() {
471476
}
@@ -960,6 +965,17 @@ public Builder customHeaderDecorator(CustomHeaderDecorator customHeaderDecorator
960965
return this;
961966
}
962967

968+
/**
969+
* Alternative Http Client
970+
*
971+
* @param alternativeHTTPModule
972+
* @return this builder
973+
*/
974+
public Builder alternativeHTTPModule(CustomHttpModule alternativeHTTPModule) {
975+
_alternativeHTTPModule = alternativeHTTPModule;
976+
return this;
977+
}
978+
963979
/**
964980
* Thread Factory
965981
*
@@ -971,7 +987,7 @@ public Builder threadFactory(ThreadFactory threadFactory) {
971987
return this;
972988
}
973989

974-
public SplitClientConfig build() {
990+
private void verifyRates() {
975991
if (_featuresRefreshRate < 5 ) {
976992
throw new IllegalArgumentException("featuresRefreshRate must be >= 5: " + _featuresRefreshRate);
977993
}
@@ -980,35 +996,19 @@ public SplitClientConfig build() {
980996
throw new IllegalArgumentException("segmentsRefreshRate must be >= 30: " + _segmentsRefreshRate);
981997
}
982998

983-
switch (_impressionsMode) {
984-
case OPTIMIZED:
985-
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 300 : Math.max(60, _impressionsRefreshRate);
986-
break;
987-
case DEBUG:
988-
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 60 : _impressionsRefreshRate;
989-
break;
990-
}
991-
992999
if (_eventSendIntervalInMillis < 1000) {
9931000
throw new IllegalArgumentException("_eventSendIntervalInMillis must be >= 1000: " + _eventSendIntervalInMillis);
9941001
}
9951002

9961003
if (_metricsRefreshRate < 30) {
9971004
throw new IllegalArgumentException("metricsRefreshRate must be >= 30: " + _metricsRefreshRate);
9981005
}
999-
1000-
if (_impressionsQueueSize <=0 ) {
1001-
throw new IllegalArgumentException("impressionsQueueSize must be > 0: " + _impressionsQueueSize);
1002-
}
1003-
1004-
if (_connectionTimeout <= 0) {
1005-
throw new IllegalArgumentException("connectionTimeOutInMs must be > 0: " + _connectionTimeout);
1006-
}
1007-
1008-
if (_readTimeout <= 0) {
1009-
throw new IllegalArgumentException("readTimeout must be > 0: " + _readTimeout);
1006+
if(_telemetryRefreshRate < 60) {
1007+
throw new IllegalStateException("_telemetryRefreshRate must be >= 60");
10101008
}
1009+
}
10111010

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

1024-
if (_numThreadsForSegmentFetch <= 0) {
1025-
throw new IllegalArgumentException("Number of threads for fetching segments MUST be greater than zero");
1026-
}
1027-
1028-
if (_authRetryBackoffBase <= 0) {
1029-
throw new IllegalArgumentException("authRetryBackoffBase: must be >= 1");
1030-
}
1031-
1032-
if (_streamingReconnectBackoffBase <= 0) {
1033-
throw new IllegalArgumentException("streamingReconnectBackoffBase: must be >= 1");
1034-
}
1035-
10361024
if (_authServiceURL == null) {
10371025
throw new IllegalArgumentException("authServiceURL must not be null");
10381026
}
@@ -1044,31 +1032,83 @@ public SplitClientConfig build() {
10441032
if (_telemetryURl == null) {
10451033
throw new IllegalArgumentException("telemetryURl must not be null");
10461034
}
1035+
}
10471036

1048-
if (_onDemandFetchRetryDelayMs <= 0) {
1049-
throw new IllegalStateException("streamingRetryDelay must be > 0");
1037+
private void verifyAllModes() {
1038+
switch (_impressionsMode) {
1039+
case OPTIMIZED:
1040+
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 300 : Math.max(60, _impressionsRefreshRate);
1041+
break;
1042+
case DEBUG:
1043+
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 60 : _impressionsRefreshRate;
1044+
break;
1045+
case NONE:
1046+
break;
10501047
}
10511048

1052-
if(_onDemandFetchMaxRetries <= 0) {
1053-
throw new IllegalStateException("_onDemandFetchMaxRetries must be > 0");
1049+
if (_impressionsQueueSize <=0 ) {
1050+
throw new IllegalArgumentException("impressionsQueueSize must be > 0: " + _impressionsQueueSize);
10541051
}
1055-
10561052
if(_storageMode == null) {
10571053
_storageMode = StorageMode.MEMORY;
10581054
}
1059-
1060-
if(_telemetryRefreshRate < 60) {
1061-
throw new IllegalStateException("_telemetryRefreshRate must be >= 60");
1062-
}
10631055

10641056
if(OperationMode.CONSUMER.equals(_operationMode)){
10651057
if(_customStorageWrapper == null) {
10661058
throw new IllegalStateException("Custom Storage must not be null on Consumer mode.");
10671059
}
10681060
_storageMode = StorageMode.PLUGGABLE;
10691061
}
1062+
}
1063+
1064+
private void verifyNetworkParams() {
1065+
if (_connectionTimeout <= 0) {
1066+
throw new IllegalArgumentException("connectionTimeOutInMs must be > 0: " + _connectionTimeout);
1067+
}
1068+
1069+
if (_readTimeout <= 0) {
1070+
throw new IllegalArgumentException("readTimeout must be > 0: " + _readTimeout);
1071+
}
1072+
if (_authRetryBackoffBase <= 0) {
1073+
throw new IllegalArgumentException("authRetryBackoffBase: must be >= 1");
1074+
}
1075+
1076+
if (_streamingReconnectBackoffBase <= 0) {
1077+
throw new IllegalArgumentException("streamingReconnectBackoffBase: must be >= 1");
1078+
}
1079+
1080+
if (_onDemandFetchRetryDelayMs <= 0) {
1081+
throw new IllegalStateException("streamingRetryDelay must be > 0");
1082+
}
1083+
1084+
if(_onDemandFetchMaxRetries <= 0) {
1085+
throw new IllegalStateException("_onDemandFetchMaxRetries must be > 0");
1086+
}
1087+
}
1088+
1089+
private void verifyAlternativeClient() {
1090+
if (_alternativeHTTPModule != null && _streamingEnabled) {
1091+
throw new IllegalArgumentException("Streaming feature is not supported with Alternative HTTP Client");
1092+
}
1093+
}
1094+
1095+
public SplitClientConfig build() {
1096+
1097+
verifyRates();
1098+
1099+
verifyAllModes();
1100+
1101+
verifyEndPoints();
1102+
1103+
verifyNetworkParams();
1104+
1105+
verifyAlternativeClient();
1106+
1107+
if (_numThreadsForSegmentFetch <= 0) {
1108+
throw new IllegalArgumentException("Number of threads for fetching segments MUST be greater than zero");
1109+
}
10701110

1071-
return new SplitClientConfig(
1111+
return new SplitClientConfig(
10721112
_endpoint,
10731113
_eventsEndpoint,
10741114
_featuresRefreshRate,
@@ -1120,7 +1160,8 @@ public SplitClientConfig build() {
11201160
_threadFactory,
11211161
_flagSetsFilter,
11221162
_invalidSetsCount,
1123-
_customHeaderDecorator);
1163+
_customHeaderDecorator,
1164+
_alternativeHTTPModule);
11241165
}
11251166
}
11261167
}

client/src/main/java/io/split/client/SplitFactoryBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.split.inputValidation.ApiKeyValidator;
44
import io.split.grammar.Treatments;
5+
import io.split.service.SplitHttpClient;
56
import io.split.storages.enums.StorageMode;
67
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;

0 commit comments

Comments
 (0)